【计算几何】【圆的交点】Navigation

 传送门:http://lx.lanqiao.cn/problem.page?gpid=T472

问题描述
  全球定位系统(GPS)是一个导航系统,根据一些在距地表大约20,000千米的轨道运行的卫星。每个卫星在一个已知的轨道上运行,发射编码着当前时间的无线电信号。如果一个装有全球定位系统的交通工具有一个非常精确的时钟,它就可以比较它自己的当地时间和从卫星上接受到的编码成信号的时间。因为无线电信号按一个已知的速度传播,所以这个交通工具能够计算出它目前的位置和信号发出时卫星的位置之间的距离。通过测算这个交通工具和一些在已知轨道上运行的卫星之间的距离,它可以非常精确地计算出自己的位置。

你必须写一个简单的“自动导航装置”程序,根据GPS的导航。为了让这个问题更简单,我们描述一个二维的问题。换句话说,你不需要考虑地球的曲率或者卫星的高度。此外,这个问题使用了更加适合于飞机和声波的速度而不是卫星和无线电波。
  给定一组移动的信号源,你的程序必须计算出在笛卡尔平面内的接收点。然后,给定一个在平面内的目标点,你的程序必须计算出从接收点到目标点指南针的指向。所有的指南针的指向用角度表示。指南针指向0(北)相当于Y轴方向,指南针指向90(东)相当于X轴方向,就像图1所展示的那样。
  在这里插入图片描述
输入格式
  读入包含多组测试数据。
  每组数据的第一行包含一个整数N (1 ≤ N ≤ 10),表示信号源的数量。接下来有3个浮点数:t,x和y。这里,t表示当所有的信号被接收时精确的当地时间,从基准时间(0时刻)按秒计时算起;x和y表示在笛卡尔平面内目标点的坐标。接下来N行每行包含4个浮点数,携带有1个信号源的信息。前2个数字表示信号源在基准时间在笛卡尔平面内的位置。第3个数字表示信号源向指南针指向D(0 ≤ D < 360)前进。第4个数字是编码在信号里的时间——也就是,信号发出的时间,从基准时间按秒计时算起。输入文件所有数字小于10000,没有一个浮点数在小数点后超过5位。
  最后一组数据的接下来一行包含4个0。
  坐标系的单位距离是1m。假设每个信号源以100m/s的速度在笛卡尔平面上移动,信号以350m/s的速度传播。由于时钟同步的不精确,你计算的距离都只精确到0.1m。也就是说,如果2个点相距0.1m以内,你应该把它们看成相同的点。信号可能在传播途中被干扰,所以接收到的多个信号可能会矛盾。
输出格式
  对于每组数据,输出数据的编号和从接收位置到目的地指南针的指向,用角度表示,四舍五入到整数。使用在样例输出中展示的标识。如果信号包含不够多的信息来计算接收位置(也就是,符合所有信号的超过一个位置),输出“Inconclusive”。如果信号矛盾(也就是,没有位置符合所有的信号),输出“Inconsistent”。如果接收位置相距目的地0.1m以内,输出“Arrived”。如果情形是Inconclusive或者Inconsistent,那么你不需要考虑Arrived的情形。
  图2对应着样例的第一个数据。t=0时3个卫星的位置A(-100,350),B(350,-100),和C(350,800)。被GPS装置接收的信号都在t=1.75时被发出,当卫星处在位置A’,B’,C’的时候(然而,通常被GPS装置接收的信号发出的时刻是不同的)。3个卫星发出信号在t=2.53571时刻汇聚在D,意味着D是接收信号的GPS装置的位置。从点D出发,指南针指向45度最终会到达目的地(1050,1050)。


 很啰嗦的一道题……大致意思是这样,各个卫星在某个时间会发出无线电波,一段时间后会被接收站接受,求解出接收站的位置。我们知道,波的边界是圆形,这题本质就是让我们求圆形的交。如果接收站正常的话,应该是位于所有圆的边界上,也就是所有圆形的统一交点。这个题目的结果就是根据是否有交点,是否有唯一交点来分类的。如果有唯一交点,还需要求出目标点基于它的角度指向。
 首先我们求出两两圆的交点并记录(如果两圆不相交,直接输出Inconsistent)。然后对每一个交点,检查它是否在所有的圆上,如果是,那么它是我们的潜在接收站之一。然后判断符合的这些点是否在误差允许范围内属于同一个点,如果没有点的话是Inconsistent,多个点的话就是Inconclusive。
 说实话这题的误差范围有点玄学,基本靠蒙,某个参数大了或者小了就容易全盘皆错。而且题目中“如果2个点相距0.1m以内,你应该把它们看成相同的点”有点让人蛋疼,不禁想到如果是很多个点相差0.1m,是否该看成同一个点。我后来是让点集合的直径不超过0.1m算作相同,反正对了就算了。
 另外如果是n=1,需要直接特判掉。
 总得来说,思想很简单,但是花了我不少时间,因为有不少细节和特殊情况要考虑。

#include<cstdio>
#include<cmath>
#include<complex>
#include<algorithm>
using namespace std;

typedef long double db;
typedef complex<db> Point;
typedef Point Vector; 

const db pi=acosl(-1);

struct Circle
{
	Point c;
	db r;
	Circle(Point c=0, db r=0):c(c),r(r){}
	Point point(db a)
	{
		return (Point){c.real()+cosl(a)*r,c.imag()+sinl(a)*r};
	}
}O[12];

db l,u,v,px,py,deg,sta,ed,vx,vy,t;
int n,kase,cn,an;
Point res[2],C[305],ans[305],F;

db ang(Vector v)
{
	return atan2l(v.imag(),v.real());
}

int dcmp(db x)
{
	if(abs(x)<1E-2L)
		return 0;
	return x<0?-1:1;
}

int getCircleCircleIntersection(Circle C1, Circle C2)
{
	db d=abs(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(abs(C1.r-C2.r)-d)>0)
		return 0;
	db a=ang(C2.c-C1.c);
	db da=acosl((C1.r*C1.r+d*d-C2.r*C2.r)/(2*C1.r*d));
	res[0]=C1.point(a-da),res[1]=C1.point(a+da);
	if(dcmp(abs(res[0]-res[1]))==0)
		return 1;
	return 2;
}

bool OnCircle(Point x, Circle c)
{
	return dcmp(abs(x-c.c)-c.r)==0;
}

int main()
{
	while(scanf("%d%Lf%Lf%Lf",&n,&ed,&u,&v)&&n)
	{
		for(int i=1;i<=n;i++)
		{
			scanf("%Lf%Lf%Lf%Lf",&px,&py,&deg,&sta);
			vx=cosl(t=pi/2-deg/180*pi)*100;
			vy=sinl(t)*100;
			px+=vx*sta;
			py+=vy*sta;
			O[i]=(Circle){(Point){px,py},(ed-sta)*350};
		}
		bool incos=false;
		cn=0;
		for(int i=1,t;i<n&&!incos;i++)
			for(int j=i+1;j<=n&&!incos;j++)
			{
				t=getCircleCircleIntersection(O[i],O[j]);
				if(t==0)
					incos=true;
				else if(t>0)
				{
					C[++cn]=res[0];
					if(t==2)
						C[++cn]=res[1];
				}
			}
		an=0;
		for(int i=1,p;i<=cn;i++)
		{
			p=0;
			for(int j=1;j<=n;j++)
				if(OnCircle(C[i],O[j]))
					++p;
			if(p==n)
				ans[++an]=C[i];
		}
		printf("Trial %d: ",++kase);
		if(incos||an==0&&n>1)
			puts("Inconsistent");
		else
		{
			bool f=true;
			for(int i=1;i<=an&&f;i++)
				for(int j=1;j<=an&&f;j++)
					if(abs(ans[i]-ans[j])>0.1L)
						f=false;
			if(!f||an==0)
				puts("Inconclusive");
			else
			{
				F=(Point){u,v};
				if(abs(F-ans[1])<0.1L)
					puts("Arrived");
				else
					printf("%d degrees\n",(int)(90-ang(F-ans[1])/pi*180+0.5));
			}
		}
	}
	return 0;
}
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值