hdu 4946 Area of Mushroom 凸包

题目链接

这个题终于让我知道了什么是凸包…

注意的点
1.只用考虑速度最大的人,因为只要 vi<vj ,在无穷远处,必然是 tj<ti
2.如果最大速度为0,那么所有答案均为0,每个人不能移动,所以不可能负责无限的区域。
3.如果两点速度相同并且位置相同,则均为0。
4.对速度最大的点进行凸包,围在里面的点不能到达无穷的区域,只有在边界上的点才行。
3.在进行进行凸包之前不能剔除那些速度最大且位置相同的点,虽然他们答案一定是0,因为如果剔除了,有些本该围在凸包内的点就成了外围点,本来答案是0的点就成了1。
4.凸包边界上如果存在3点共线的情况这个题是需要保留中间点的,但是凸包模板上没有保留,之前我直接将叉乘<=0改为<0,意思是只有在右边时,栈才会弹出元素,如果共线不会弹出。结果这样做是完全错误的。因为这样可能形成的不是凸包,而是“凹包”,因为如果栈中栈顶上的两个点位置相同,那么叉积自然为0,所以就可以随便放东西进去,这样很可能就成了一个凹多边形。
5.正确的方法是,先进行凸包,删除共线的点,然后对所有速度最大并且没有点与之位置相同的点进行检测,看它是否在凸包的边界上,如果是答案为1,否则为0。

#include<cstdio>
#include<string>
#include<cstring>
#include<iostream>
#include<cmath>
#include<algorithm>
#include<vector>
using namespace std;

#define all(x) (x).begin(), (x).end()
#define for0(a, n) for (int (a) = 0; (a) < (n); (a)++)
#define for1(a, n) for (int (a) = 1; (a) <= (n); (a)++)
#define mes(a,x,s)  memset(a,x,(s)*sizeof a[0])
#define mem(a,x)  memset(a,x,sizeof a)
#define ysk(x)  (1<<(x))
#define sqr(x)  ((x)*(x))
typedef long long ll;
typedef pair<int, int> pii;
const int INF =0x3f3f3f3f;
const int maxn= 500   ;
const double PI=acos(-1.0);
const double eps=1e-10;
int dcmp(double x)
{
    if(fabs(x)<eps)  return 0;
    else return x<0?-1:1;
}
struct Point
{
    double x,y;int v,id;
    Point(double x=0,double y=0):x(x),y(y) {};
    bool operator ==(const Point B)const {return dcmp(x-B.x)==0&&dcmp(y-B.y)==0;}

    bool operator<(const Point& b)const
    {
        return dcmp(x-b.x)<0|| dcmp(x-b.x)==0 &&dcmp(y-b.y)<0;
    }
};
bool cmp(Point a,Point b)//这个排序很实用,现将速度从大到小排,方便处理,同时将位置靠近的排在一起。
{
    if(a.v==b.v) return dcmp(a.x-b.x)<0|| dcmp(a.x-b.x)==0 &&dcmp(a.y-b.y)<0;
    return a.v>b.v;
}
typedef Point Vector;
Vector operator -(Vector A,Vector B) {return Vector(A.x-B.x,A.y-B.y); }

double Cross(Vector A,Vector B) { return A.x*B.y-A.y*B.x;}

double Dot(Vector A,Vector B) {return A.x*B.x+A.y*B.y;}

bool OnSegment(Point p,Point a1,Point a2)
{
    return dcmp(Cross(a1-p,a2-p)  )==0&&dcmp(Dot(a1-p,a2-p)  )<=0;
}

int n,npo2;Point po[maxn+10],po2[maxn+10],chp[2*maxn+10];bool no[maxn+10],ans[maxn+10];

void ConvexHell(Point *p,int n,Point *ch)
{
    sort(p,p+n);
     int m=0;
    for(int i=0;i<n;i++)
    {
        while(m>1&&Cross(ch[m-1]-ch[m-2],p[i]-ch[m-1]   )<=0   )  m--;
        ch[m++]=p[i];
     }
    int k=m;
    for(int i=n-2;i>=0;i--)
    {
        while(m>k &&Cross(ch[m-1]-ch[m-2],p[i]-ch[m-1] )<=0)   m--;
        ch[m++]=p[i];
    }
    if(n>1)  m--;
    for0(i,npo2)
    {
        if(no[po[i].id ])  continue;
        bool ok=false;
        for(int j=0;j<m&&!ok;j++)
        {
           if(OnSegment(po[i],ch[j],ch[(j+1)%m])) ok=true;
        }
        if(ok)  ans[po[i].id ]=1;
    }
//    return m;

}


bool same(Point & a,Point b)
{
    return dcmp(a.x-b.x)==0&&dcmp(a.y-b.y)==0;
}
int main()
{
   std::ios::sync_with_stdio(false);
   int kase=0;
   while(cin>>n&&n)
   {
       mes(no,0,n);mes(ans,0,n);

       for0(i,n)  {cin>>po[i].x>>po[i].y>>po[i].v;po[i].id=i;}
       sort(po,po+n,cmp);
       int t;
       for(t=1;t<n;t++)
       {
             if(po[t-1].v!=po[t].v) break;
             if(same(po[t-1],po[t]))  no[po[t].id ]=no[po[t-1].id ]=1;
       }
       if(po[0].v==0) t=0;
       for0(i,t)  po2[i]=po[i];
       npo2=t;
       ConvexHell(po2,npo2,chp);
       printf("Case #%d: ",++kase);
       for0(i,n)
       {
           if(ans[i])  putchar('1');
           else  putchar('0');
       }putchar('\n');


   }

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值