Hdu 4946 Area of Mushroom

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
*/

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值