题目链接:
题目大意:
假设地球是一个球体,给出起点的经纬度
A(x1,y1),
终点的经纬度
B(x2,y2)
。
x:
纬度,北纬为正,南纬为负;
y:
经度,东经为正,西经为负。
令:
D1
为两点的距离;
D2
为起点
A
先沿着纬线,再沿着经线 走到终点
求D1,D2
。
数据范围:
1≤T≤10000
∣x1∣,∣x2∣≤90,∣y1∣,∣y2∣≤180
解题思路:
这道题不重要,重要的是怎么求地球上两点的距离。
图的话,将就看这个吧!懒得画了,,,只看图就好,,,
球面坐标和直角坐标存在一一对应的关系:球面有一点
M(r,φ,θ)
,
则,点
M
的直角坐标和球面坐标的关系为:
设A(r,α,β),B(r,φ,θ) ,
则有OA→=(rcosαcosβ,rcosαsinβ,rsinα),OB→=(rcosφcosθ,rcosφsinθ,rsinφ)
由此可得,夹角 ang=arccos(OA→⋅OB→∣OA→∣⋅∣OB→∣)
化简得: ang=arccos(cosαcosφcos(β−θ)+sinαsinφ)
夹角出来了,距离就好办了。
代码:
//化为弧度制
double rad(double d) {
return d * PI / 180.0;
}
//求两点之间的距离
double dis(Point A, Point B) {
A.x = rad(A.x); A.y = rad(A.y);
B.x = rad(B.x); B.y = rad(B.y);
double ang = acos(cos(A.x) * cos(B.x) * cos(A.y - B.y) + sin(A.x) * sin(B.x));
double s = ang * R; //R为地球半径
return s;
}
我还看到一个公式,但我不知道怎么推出来的,若有好心大佬,求解答。
double dis(Point A, Point B) {
double Theta = A.x - B.x;
double Beta = A.y - B.y;
double ang = 2 * asin(sqrt(sin(Theta / 2) * sin(Theta / 2) + cos(A.x) * cos(B.x) * sin(Beta / 2) * sin(Beta / 2)));
double s = ang * R;
return s;
}
距离的问题解决了,其他都不重要了。不对,这道题还没完呢!,,,
有一个坑点:当一个点在东半球,另一个在西半球时,需要特别注意一下角度,稍微想想。
AC代码:
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cmath>
#include <algorithm>
#include <queue>
#include <set>
#include <iostream>
using namespace std;
typedef long long LL;
const int inf = 1 << 30;
const LL INF = 1LL << 60;
const double PI = acos(-1.0);
const double R = 6371.0;
int T;
struct Point {
double x, y;
};
Point a, b, c;
//化为弧度制
double rad(double d) {
return d * PI / 180.0;
}
//求弧长
double arc(double Theta, double r) {
return Theta * r;
}
//求两点之间的距离
double dis(Point A, Point B) {
A.x = rad(A.x); A.y = rad(A.y);
B.x = rad(B.x); B.y = rad(B.y);
double ang = acos(cos(A.x) * cos(B.x) * cos(A.y - B.y) + sin(A.x) * sin(B.x));
/*这个公式也可以,但我不知道是怎么推的
double Theta = A.x - B.x;
double Beta = A.y - B.y;
double ang = 2 * asin(sqrt(sin(Theta / 2) * sin(Theta / 2) + cos(A.x) * cos(B.x) * sin(Beta / 2) * sin(Beta / 2)));
*/
double s = ang * R;
return s;
}
int main()
{
scanf("%d", &T);
while(T--) {
scanf("%lf %lf %lf %lf", &a.x, &a.y, &b.x, &b.y);
//这个稍微想想就明白了,一个小坑点
if(abs(a.y - b.y) > 180.0) {
if(a.y < 0.0) a.y += 360.0;
else if(b.y < 0.0) b.y += 360.0;
}
c.x = a.x; c.y = b.y;
double r = R * cos(rad(a.x));
printf("%.10lf %.10lf\n", dis(a, b), dis(b, c) + arc(rad(abs(a.y - b.y)), r));
}
return 0;
}