Teacher Mai has a kingdom with the infinite area.
He has n students guarding the kingdom.
The i-th student stands at the position (xi,yi), and his walking speed is vi.
If a point can be reached by a student, and the time this student walking to this point is strictly less than other students, this point is in the charge of this student.
For every student, Teacher Mai wants to know if the area in the charge of him is infinite.
题意说的是在平面内有n个守卫,他们的坐标和速度给定,平面内任一点,如果其中一个守卫到达的时间严格小于其他守卫则这个点是这个守卫守护的,如果一个守卫守护的面积是无穷大,则用1表示,否则用0表示。
首先如果速度为零,那么他守护的面积就是0,所以输出0。考虑两个点,如果其中一个点比另一个点的速度大,那么速度小的那个点的面积肯定是有限的,那么就说明,无穷面积只能出现在拥有最大速度的点中,并且是这些点构成的凸包上的点,但是,题目中存在两个守卫在同一个点并且有相同的速度,如果这样的点在凸包上,就把他们赋成0,因为时间是相等并不是严格小。
思想就是这样,计算几何码的比较复杂,附上队友写的代码,供参考。
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
using namespace std;
#define N 1024
int n;
double l;
const double eps=1e-9;
typedef struct node
{
int x,y;
double rad;
int id,speed;
}Point;
Point point[N],chs[N],tpoint[N];
int GetDis(Point a,Point b)
{
return (a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y);
}
bool cmp1(Point a,Point b)
{
if(a.y==b.y) return a.x<b.x;
else return a.y<b.y;
}
bool cmp2(Point a,Point b)
{
if(fabs(a.rad-b.rad)<eps)
return GetDis(a,point[0])<GetDis(b,point[0]);
else return a.rad<b.rad;
}
double GetRadium(Point a,Point b)
{
return atan2(1.0*(b.y-a.y),1.0*(b.x-a.x));
}
bool pingxing(Point a,Point b,Point c)
{
return (b.x-a.x)*(c.y-a.y)-(b.y-a.y)*(c.x-a.x)==0;
}
int xmuti(Point p0,Point p1,Point p2){
return (p1.x-p0.x)*(p2.y-p1.y)-(p1.y-p0.y)*(p2.x-p1.x);
}
int ans[N];
int main()
{
int t=1;
while(scanf("%d",&n),n){
int m=-1;
memset(ans,0,sizeof(ans));
for(int i=0;i<n;i++)
{
scanf("%d%d%d",&tpoint[i].x,&tpoint[i].y,&tpoint[i].speed);
tpoint[i].id=i;
m=max(m,tpoint[i].speed);
}
printf("Case #%d: ",t++);
int cnt=0;
if(m==0)
{
for(int i=0;i<n;i++) printf("0");
printf("\n");
continue;
}
for(int i=0;i<n;i++)
{
if(tpoint[i].speed!=m)
continue;
bool ok=1;
for(int j=0;j<cnt;j++)
{
if(point[j].x==tpoint[i].x&& point[j].y==tpoint[i].y)
{
ok=0;
break;
}
}
if(ok)
point[cnt++]=tpoint[i];
}
//printf("%d\n",cnt);
if(cnt<=3)
{
for(int i=0;i<cnt;i++) ans[point[i].id]=1;
for(int i=0;i<n;i++)
{
for(int j=0;j<n;j++)
{
if(i==j) continue;
if(tpoint[i].x==tpoint[j].x&&tpoint[i].y==tpoint[j].y&&tpoint[i].speed==tpoint[j].speed)
{
ans[tpoint[i].id]=0;
break;
}
}
}
for(int i=0;i<n;i++) printf("%d",ans[i]);
printf("\n");
continue;
}
sort(point,point+cnt,cmp1); //出最左下方的点
for(int i=0;i<cnt;i++) //得出每个点和基准点连线与x轴的夹角
point[i].rad=GetRadium(point[0],point[i]);
sort(point+1,point+cnt,cmp2); //按夹角排序
chs[0]=point[0],chs[1]=point[1];
int top=1;
for(int i=2;i<cnt;i++)
{
while(top&&xmuti(chs[top-1],chs[top],point[i])<0)
top--;
chs[++top]=point[i];
}
//for(int i=0;i<=top;i++)
// printf("%d?",chs[i].id);
int tep=top,i;
for(i=cnt-2;i>=0;i--)
if(pingxing(point[i],point[cnt-1],point[0]))
chs[++top]=point[i];
else
break;
if(i<0)
top=tep+1;
else
top++;
//printf("%d %d %d\n",top,tep,i);
for(int i=0;i<top;i++)
ans[chs[i].id]=1;
for(int i=0;i<n;i++)
{
for(int j=0;j<n;j++)
{
if(i==j) continue;
if(tpoint[i].x==tpoint[j].x&&tpoint[i].y==tpoint[j].y&&tpoint[i].speed==tpoint[j].speed)
{
ans[tpoint[i].id]=0;
break;
}
}
}
for(int i=0;i<n;i++)
{
printf("%d",ans[i]);
}
printf("\n");
}
return 0;
}
/*
0 0 2
1 0 2
2 0 2
3 0 2
4 0 2
5 0 2
1 1 2
2 2 2
3 3 2
4 4 2
5 5 2
0 1 2
0 2 2
0 3 2
0 4 2
0 5 2
*/