1 条题解

  • 0
    @ 2025-5-6 2:15:56

    解题思路:

    本题要求判断地面上的位置能否直接观测到卫星。卫星必须位于该位置的地平线上方,即视线不被地球阻挡。地球被视为完美球体,半径为63786378公里。卫星的可见性通过几何计算确定。

    关键步骤:

    坐标转换:将地理坐标(纬度、经度)(纬度、经度)转换为三维笛卡尔坐标。

    • 纬度转换为球坐标系中的极角,经度转换为方位角。
    • 地球表面点的坐标为 (R,纬度,经度)(R, 纬度, 经度),卫星的坐标为 (R+高度,纬度,经度)(R + 高度, 纬度, 经度)

    判断可见条件

    • 计算地面点与卫星连线相对于地球中心的夹角。
    • 若该夹角的余弦值满足 cosθR/(R+高度)cosθ ≥ R/(R + 高度),则卫星可见。
    • 通过向量点积计算余弦值,避免直接处理角度。

    浮点精度处理

    • 使用极小值常量 EPSEPS 处理浮点数比较误差,确保判断的准确性。

    C++实现

    #include <cstdio>
    #include <cmath>
    using namespace std;
    
    // 定义圆周率常量
    static const double PI = acos(-1.0);
    // 定义极小值常量用于浮点数比较
    static const double EPS = 1e-6;
    
    // 三维坐标结构体,表示地球表面上或卫星的位置
    struct P3 {
       double x, y, z; // 三个坐标轴分量
       P3() {} // 默认构造函数
       P3(double a, double b, double c) : x(a), y(b), z(c) {} // 带参数的构造函数
    };
    
    // 计算两个三维向量的点积
    inline double dot(const P3& p, const P3& q) {
       return p.x * q.x + p.y * q.y + p.z * q.z;
    }
    
    // 计算三维向量的模长(绝对值)
    inline double abs(const P3& p) {
       return sqrt(dot(p, p));
    }
    
    // 地球半径常量(单位:公里)
    static const double R = 6378;
    
    // 将地理坐标(纬度、经度)转换为笛卡尔坐标系下的点
    P3 from_polar(double lat, double lan, double r) {
       // 将角度转换为弧度
       lat = lat / 180.0 * PI;
       lan = lan / 180.0 * PI;
       // 根据球面坐标公式计算三维坐标
       double x = r * cos(lat) * cos(lan);
       double y = r * cos(lat) * sin(lan);
       double z = r * sin(lat);
       return P3(x, y, z);
    }
    
    int main() {
       int N; // 待检查的位置数量
       // 处理多个测试用例,直到输入N=0为止
       for (int Ti = 1; scanf("%d", &N) != EOF && N != 0; Ti++) {
           double lat, lan, height;
           // 读取卫星的纬度、经度和高度
           scanf("%lf %lf %lf", &lat, &lan, &height);
           // 将卫星坐标转换为笛卡尔坐标系下的点(距离地球表面高度为height)
           const P3 sat = from_polar(lat, lan, R + height);
           // 计算临界余弦值u = R / (R + height)
           const double u = R / (R + height);
           printf("Test case %d:\n", Ti); // 输出测试用例编号
           // 遍历每个待检查的地面位置
           for (int i = 0; i < N; i++) {
               char name[128]; // 存储位置标签
               // 读取位置标签、纬度和经度
               scanf("%s %lf %lf", name, &lat, &lan);
               // 将地面位置转换为笛卡尔坐标系下的点(地球表面)
               const P3 p = from_polar(lat, lan, R);
               // 计算卫星向量与地面点向量的夹角余弦值
               const double t = dot(sat, p) / (abs(sat) * abs(p));
               // 如果余弦值接近或超过临界值u,则卫星可见
               if (u - t < EPS) {
                   puts(name); // 输出可见的位置标签
               }
           }
           putchar('\n'); // 每个测试用例后输出空行
       }
       return 0;
    }
    
    • 1

    信息

    ID
    1572
    时间
    1000ms
    内存
    256MiB
    难度
    10
    标签
    递交数
    3
    已通过
    1
    上传者