(beginer) 经纬度转换 UVA 10075 - Airlines

Problem A

Airlines

Input: standard input

Output: standard output

 

A leading airlines company has hired you to write a program that answers the following query: given a list of city locations (latitudes and longitudes) and a list of direct flights what is the minimum distance a passenger needs to fly to get from a given city to another?

 

To get from a city to another a passenger may either take a direct flight (if exists) or take a sequence of connecting flights (if there exists such a route).

 

Assume that if a passenger takes a direct flight from X to Y he never flies more than the geographical distance between X and Y.  The geographical distance between two locations X and Y is the length of the geodetic line segment connecting X and Y. The geodetic line segment between two points on a sphere is the shortest connecting curve lying entirely in the surface of the sphere. Assume that the Earth is a perfect sphere with a radius of exactly 6378-km and the value of p is approximately 3.141592653589793. Round the geographical distance between every pair of cities to the nearest integer.

 

Input

The input may contain multiple test cases.

 

The first line of each test case contains three integers N (N <= 100), M (M <= 300) and Q (Q <= 10000) where N indicates the number of cities, M represents the number of direct flights and Q is the number of queries.

 

The next N lines contain the city list. The i-th of these N lines will contain a string ci followed by two real numbers lti and lni, representing the city name, its latitude and longitude respectively. The city name will be no longer than 20 characters and will not contain white-space characters. The latitude will be between -90 (South Pole) and +90 (North Pole). The longitude will be between -180 and +180 where negative numbers denote locations west of the meridian and positive numbers denote locations east of the meridian. (The meridian passes through Greenwich, London.)

 

The next M lines contain the direct flight list. The i-th of these M lines will contain two city names ai and bi indicating that there exists a direct flight from city ai to city bi. Be assured that both city names will occur in the city list.

 

The next Q lines contain the query list. The i-th of these Q lines will contain two city names ai and bi asking for the minimum distance a passenger needs to fly in order to get from city ai to city bi. Be assured that ai  bi are not equal and both city names will occur in the city list.

 

The input will terminate with three zeros form N, M and Q.

 

Output

For each test case in the input first output the test case number (starting from 1) as shown in the sample output. Then for each query in the input print a line giving the shortest distance (in km) a passenger needs to fly to get from the first city (ai) in the query to the second one (bi). If there exists no route form ai to bi, just print the line "no route exists".

Print a blank line between two consecutive test cases.

 

Sample Input

3 4 2
Dhaka 23.8500 90.4000
Chittagong 22.2500 91.8333
Calcutta 22.5333 88.3667
Dhaka Calcutta
Calcutta Dhaka
Dhaka Chittagong
Chittagong Dhaka
Chittagong Calcutta
Dhaka Chittagong
5 6 3
Baghdad 33.2333 44.3667
Dhaka 23.8500 90.4000
Frankfurt 50.0330 8.5670
Hong_Kong 21.7500 115.0000
Tokyo 35.6833 139.7333
Baghdad Dhaka
Dhaka Frankfurt
Tokyo Hong_Kong
Hong_Kong Dhaka
Baghdad Tokyo
Frankfurt Tokyo
Dhaka Hong_Kong
Frankfurt Baghdad
Baghdad Frankfurt
0 0 0

Sample Output

Case #1
485 km
231 km

Case #2
19654 km
no route exists
12023 km
_________________________________________________________________________________________
Rezaul Alam Chowdhury 


题意:给出地球上面机场的经纬度以及航班的路线,然后问任意两个机场的最短距离。


思路:直接转换为三维的坐标就行了,然后距离要4舍5入,算出来的时候就直接四舍五入了。直接floyd就行了。


代码:

#include<iostream>
#include<cstdio>
#include<string.h>
#include<math.h>
#include<string>
#include<cstring>
#include<map>
#include<algorithm>
#include<vector>
using namespace std;
#define eps 1e-10
const double inf = 1e16;
const double PI = 3.141592653589793;//acos(-1.0);
struct Point
{
	Point (double xx=0,double yy=0) : x(xx) , y(yy) { }
	double x;
	double y;
};

typedef Point Vector;
Vector operator+(Vector  v1,Vector  v2) { return Vector(v1.x+v2.x,v1.y+v2.y); }
Vector operator-(Vector  v1,Vector  v2) { return Vector(v1.x-v2.x,v1.y-v2.y); }
Vector operator*(Vector  v, double p) { return Vector(v.x*p,v.y*p); }
Vector operator/(Vector  v,double p) { return Vector(v.x/p,v.y/p); }

bool operator < (Point  a,Point  b) { return a.x < b.x || (a.x==b.x && a.y > b.y); }
int dcmp(double x) 
{
	if (fabs(x) < eps) return 0;
	return x < 0 ? -1 : 1; 
}
bool operator==(const Point & a,const Point & b) 
{
	return dcmp(a.x-b.x)==0 && dcmp(a.y-b.y)==0;
}

inline double toRad(double x) { return x * PI/180; }
inline double toDegreed(double rad) { return rad*180/PI; }
double Dot(Vector  A,Vector  B) { return A.x*B.x+A.y*B.y; }
double Length(Vector  A) { return sqrt(Dot(A,A)); }
double Angle(Vector A,Vector B) { return acos(Dot(A,B)/Length(A)/Length(B)); }
double Cross(Vector A,Vector B) { return A.x*B.y-A.y*B.x; }
double Area2(Point a,Point b,Point c) {  return Cross(b-a,c-a); }
Vector Rotate(Vector A,double rad) 
{
	return Vector(A.x*cos(rad)-A.y*sin(rad),A.x*sin(rad)+A.y*cos(rad));
}
Vector Normal(Vector A) { double L = Length(A); return Vector(-A.y/L,A.x/L); }

//点和直线
Point GetLineIntersection(Point P,Vector v,Point Q,Vector w)
{
	Vector u = P-Q;
	double t = Cross(w,u) / Cross(v,w);
	return P+v*t;
}

double DistanceToLine(Point P,Point A,Point B) 
{
	Vector v1 = B-A , v2 = P-A;
	return fabs(Cross(v1,v2))/Length(v1);
}
double DistanceToSegment(Point P,Point A,Point B)
{
	if (A==B) return Length(P-A);
	Vector v1 = B-A , v2 = P-A , v3 = P-B;
	if (dcmp(Dot(v1,v2)) < 0) return Length(v2);
	else if (dcmp(Dot(v1,v3)) > 0) return Length(v3);
	else return fabs(Cross(v1,v2))/Length(v1);
}
Point GetLineProjection(Point P,Point A,Point B) 
{
	Vector v = B-A;
	return A+v*(Dot(v,P-A)/Dot(v,v));
}
bool SegmentProperIntersection(Point a1,Point a2,Point b1,Point b2) 
{
	double c1 = Cross(a2-a1,b1-a1) , c2 = Cross(a2-a1,b2-a1) ,
		     c3 = Cross(b2-b1,a1-b1) , c4 = Cross(b2-b1,a2-b1);
	return dcmp(c1)*dcmp(c2) < 0 && dcmp(c3)*dcmp(c4)<0;
}
bool OnSegment(Point p,Point a,Point b) {
	return dcmp(Cross(a-p,b-p))==0 && dcmp(Dot(a-p,b-p)) < 0;
}
//--------------------------------------------------------------------------------------------
//直线和直线
struct Line
{
	Point P;				//直线上任意一点
	Vector v;				// 方向向量。它的左边就是对应的半平面
	double ang;			//极角
	Line() { }
	Line(Point P,Vector v) : P(P) , v(v) { ang = atan2(v.y,v.x); }
	bool operator < (const Line& L) const { return ang < L. ang; } //排序用的比较运算符
	Point point(double x) { return v*(x-P.x)+P; }
};

//点p在有向直线L的左边(线上不算)
bool OnLeft(Line L , Point p) { return Cross(L.v,p-L.P) > 0; }

//二直线交点。假定交点唯一存在
Point GetIntersection(Line a,Line b) 
{
	Vector u = a.P-b.P;
	double t = Cross(b.v,u) / Cross(a.v,b.v);
	return a.P+a.v*t;
}

//半平面交的过程
int HalfplaneIntersection(Line* L,int n,Point* poly)
{
	sort(L,L+n);						     //按极角排序

	int first , last;						//双端队列的第一个元素和最后一个元素的下表
	Point *p = new Point[n];		//p[i]为q[i]和q[i+1]的交点
	Line *q = new Line[n];			//双端队列
	q[first=last=0] = L[0];			//双端队列初始化为只有一个半平面L[0]
	for (int i = 1 ; i < n ; ++i) {
		while (first < last && !OnLeft(L[i],p[last-1])) --last;
		while (first < last && !OnLeft(L[i],p[first])) ++first;
		q[++last] = L[i];
		if (fabs(Cross(q[last].v,q[last-1].v)) < eps) {
			--last;
			if (OnLeft(q[last],L[i].P)) q[last] = L[i];
		}
		if (first < last) p[last-1] = GetIntersection(q[last-1],q[last]);
	}
	while (first < last && !OnLeft(q[first],p[last-1])) --last;
	//删除无用平面(*)
	if (last - first <=1 ) return 0;                    //空集(**)
	p[last] = GetIntersection(q[last],q[first]);		//计算首尾两个半平面的交点

	//从deque复制到输出中
	int m = 0;
	for (int i = first ; i <= last ; ++i) poly[m++] = p[i];
	return m ;
}


//--------------------------------------------
//与圆相关
struct Circle 
{
	Circle() { }
	Point c;
	double r;
	Circle(Point c, double r) : c(c) , r(r) { }
	Point point (double a) { return Point(c.x+cos(a)*r,c.y+sin(a)*r); }
};

int getLineCircleIntersection(Line L,Circle C,double &t1,double &t2,vector<Point>& sol)
{
	double a = L.v.x , b = L.P.x-C.c.x , c= L.v.y, d = L.P.y-C.c.y;
	double e = a*a+c*c , f = 2*(a*b+c*d) , g = b*b+d*d-C.r*C.r;
	double delta = f*f-4*e*g;				//判别式		
	if (dcmp(delta) < 0) return 0;		//相离
	if (dcmp(delta)==0) {                   //相切
		t1 = t2 = -f/(2*e); 
		sol.push_back(L.point(t1));
		return 1;
	}
	//相交
	t1 = (-f-sqrt(delta)) / (2*e); sol.push_back(L.point(t1));
	t2 = (-f+sqrt(delta))/(2*e); sol.push_back(L.point(t2));
	return 2;
}

double angle(Vector v) { return atan2(v.y,v.x); }

int getCircleCircleIntersection(Circle C1,Circle C2,vector<Point>& sol)
{
	double d = Length(C1.c-C2.c);
	if (dcmp(d)==0) {
		if (dcmp(C1.r-C2.r)==0) return -1;			//两圆重合
		return 0;
	}
	if (dcmp(C1.r+C2.r-d) < 0) return 0;
	if (dcmp(fabs(C1.r-C2.r)-d) > 0) return 0;

	double a = angle(C2.c-C1.c);
	double da = acos((C1.r*C1.r+d*d-C2.r*C2.r)/(2*C1.r*d));			//向量C1C2的极角
	//C1C2到C1P1的角
	Point p1 = C1.point(a-da) , p2 = C1.point(a+da);
	sol.push_back(p1);
	if (p1==p2) return 1;
	sol.push_back(p2);
	return 2;
}

//国电p到圆C的切线。v[i]是第i条切线的向量。返回切线条数
int getTangents(Point p,Circle C,Vector* v)
{
	Vector u= C.c-p;
	double dist = Length(u);
	if (dist < C.r) return 0;
	else if (dcmp(dist-C.r)==0) {
		v[0] = Rotate(u,PI/2);
		return 1;
	} else {
		double ang = asin(C.r/dist);
		v[0] = Rotate(u,-ang);
		v[1] = Rotate(u,+ang);
		return 2;
	}
}

int getTangents(Circle A,Circle B,Point* a, Point* b)
{
	int cnt = 0;
	if (A.r < B.r) { swap(A,B); swap(a,b); }
	double d2 = Dot(A.c-B.c,A.c-B.c);
	double rdiff = A.r-B.r;
	double rsum = A.r+B.r;
	if (dcmp(d2-rdiff*rdiff) < 0) return 0;			//内含

	double base = atan2(B.c.y-A.c.y,B.c.x-A.c.x);
	if (d2==0 && dcmp(A.r-B.r)==0) return -1;	//无限多条切线
	if (dcmp(d2-rdiff*rdiff)==0) {                       //内切,1条切线
		a[cnt] = A.point(base);
		b[cnt] = B.point(base);
		++cnt;
		return 1;
	}
	//有外切共线
	double ang = acos((A.r-B.r)/sqrt(d2));
	a[cnt] = A.point(base+ang); b[cnt] = B.point(base+ang); ++cnt;
	a[cnt] = A.point(base-ang); b[cnt] = B.point(base-ang); ++cnt;
	if (dcmp(d2-rsum*rsum)==0) {                  //一条内公切线
		a[cnt] = A.point(base);
		b[cnt] = B.point(PI+base);
		++cnt;
	} else if (dcmp(d2-rsum*rsum)>0) {           //两条公切线
		double ang = acos((A.r+B.r)/sqrt(d2));
		a[cnt] = A.point(base+ang); b[cnt] = B.point(PI+base+ang); ++cnt;
		a[cnt] = A.point(base-ang); b[cnt] = B.point(PI+base-ang); ++cnt;
	}
	return cnt;
}

bool InCircle(Circle A,Circle B)
{
	if (dcmp(A.r-B.r)>0) return false;
	double d2 = Dot(A.c-B.c,A.c-B.c);
	double rdiff = A.r-B.r;
	double rsum = A.r+B.r;
	if (dcmp(d2-rdiff*rdiff) <= 0) return true;			//内含或内切或重合
	return false;
}
//----------------------------------------------------------------------------
//与球相关的转化
//角度转换为弧度
double torad(double deg) { return deg/180*PI; }

//经纬度(角度)转化为空间坐标
void get_coord(double R,double lat,double lng,double& x,double& y,double& z)
{
	lat = torad(lat);
	lng = torad(lng);
	x = R*cos(lat)*cos(lng);
	y = R*cos(lat)*sin(lng);
	z = R*sin(lat);
}

//-----------------------------------------------------------------------
const int maxn = 100+5;
const double R = 6378;
struct ThreeDPoint : Point
{
	double z;
	ThreeDPoint(double x=0,double y=0,double z=0)
		: Point(x,y) , z(z) { }
}p[maxn];

inline double sqr(double x) { return x*x; }

int n , m , q;
map<string,int> city;
double f[maxn][maxn];
double GetDistGlobe(ThreeDPoint p1,ThreeDPoint p2)
{
	double d2 = sqr(p1.x-p2.x)+sqr(p1.y-p2.y)+sqr(p1.z-p2.z);
	double ang = acos(1-d2/(2*sqr(R)));
	return ang*R;
}

void input()
{
	char name[50];
	city.clear();
	for (int i = 0 ; i < n ; ++i) {
		scanf("%s",name);
		string s = name;
		city[s] = i;
		double lat , lng;
		scanf("%lf%lf",&lat,&lng);
		double x , y , z;
		get_coord(R,lat,lng,x,y,z);
		p[i] = ThreeDPoint(x,y,z);
	}
	for (int i = 0 ; i < n ; ++i)
		for (int j = 0 ; j < n; ++j)
			f[i][j] = inf;
	for (int i = 0 ; i < n ; ++i) f[i][i] = 0;
	while (m--) {
		string s1 , s2;
		scanf("%s",name); s1 = name;
		scanf("%s",name); s2 = name;
		if (city.count(s1)==0 || city.count(s2)==0) continue;
		int u = city[s1] , v = city[s2];
		f[u][v] = (int)(eps+0.5+GetDistGlobe(p[u],p[v]));
	}
}

void solve()
{
	//floyd
	for (int k = 0 ; k < n ; ++k)
		for (int i = 0 ; i < n ; ++i)
			for (int j = 0 ; j < n ; ++j)
				f[i][j] = min(f[i][j],f[i][k]+f[k][j]);
	char name1[50] , name2[50];
	while (q--) {
		string s1 , s2;
		scanf("%s%s",name1,name2);
		s1 = name1 , s2 = name2;
		int u = city[s1] , v = city[s2];
		if (dcmp(f[u][v]-inf)==0) { puts("no route exists"); }
		else printf("%d km\n",(int)(f[u][v]+eps+0.5));
	}
}

int main()
{
	int k = 0;
	while (scanf("%d%d%d",&n,&m,&q)==3) {
		if (n+m+q==0) return 0;
		if (k) puts("");
		input();
		++k;
		printf("Case #%d\n",k);
		solve();
	}
	return 0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值