1 条题解
-
0
解题思路:
本题要求判断地面上的位置能否直接观测到卫星。卫星必须位于该位置的地平线上方,即视线不被地球阻挡。地球被视为完美球体,半径为公里。卫星的可见性通过几何计算确定。
关键步骤:
坐标转换:将地理坐标转换为三维笛卡尔坐标。
- 纬度转换为球坐标系中的极角,经度转换为方位角。
- 地球表面点的坐标为 ,卫星的坐标为 。
判断可见条件:
- 计算地面点与卫星连线相对于地球中心的夹角。
- 若该夹角的余弦值满足 ,则卫星可见。
- 通过向量点积计算余弦值,避免直接处理角度。
浮点精度处理:
- 使用极小值常量 处理浮点数比较误差,确保判断的准确性。
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
- 上传者