POJ1228(稳定凸包问题)


分类: 计算几何   381人阅读  评论(0)  收藏  举报

题目:Grandpa's Estate

 

题意:输入一个凸包上的点(没有凸包内部的点,要么是凸包顶点,要么是凸包边上的点),判断这个凸包是否稳定。所谓稳

定就是判断能不能在原有凸包上加点,得到一个更大的凸包,并且这个凸包包含原有凸包上的所有点。

 

分析:容易知道,当一个凸包稳定时,凸包的每条边上都要有至少三个点,若只有两个点,则可以增加一个点,得到更大的凸

包。这样我们可以求出凸包,在求凸包时把共线的点也加进来,这样我们就判断是否有连续的三点共线即可,具体参见代码。

[cpp]  view plain copy
  1. #include <iostream>  
  2. #include <algorithm>  
  3. #include <stdio.h>  
  4. #include <math.h>  
  5.   
  6. using namespace std;  
  7.   
  8. const int N = 40005;  
  9.   
  10. typedef double DIY;  
  11.   
  12. struct Point  
  13. {  
  14.     DIY x,y;  
  15. };  
  16.   
  17. Point p[N];  
  18. Point stack[N];  
  19. Point MinA;  
  20.   
  21. int top;  
  22.   
  23. DIY dist(Point A,Point B)  
  24. {  
  25.     return sqrt((A.x-B.x)*(A.x-B.x)+(A.y-B.y)*(A.y-B.y));  
  26. }  
  27.   
  28. DIY cross(Point A,Point B,Point C)  
  29. {  
  30.     return (B.x-A.x)*(C.y-A.y)-(B.y-A.y)*(C.x-A.x);  
  31. }  
  32.   
  33. bool cmp(Point a,Point b)  
  34. {  
  35.     DIY k=cross(MinA,a,b);  
  36.     if(k>0) return 1;  
  37.     if(k<0) return 0;  
  38.     return dist(MinA,a)<dist(MinA,b);  //这里共线的点按距离从小到大排序  
  39. }  
  40.   
  41. void Graham(int n)  
  42. {  
  43.     int i;  
  44.     for(i=1; i<n; i++)  
  45.         if(p[i].y<p[0].y||(p[i].y==p[0].y&&p[i].x<p[0].x))  
  46.             swap(p[i],p[0]);  
  47.     MinA=p[0];  
  48.     sort(p+1,p+n,cmp);  
  49.     stack[0]=p[0];  
  50.     stack[1]=p[1];  
  51.     top=1;  
  52.     for(i=2; i<n; i++)  
  53.     {  
  54.         //注意这里我们把共线的点也压入凸包里  
  55.         while(cross(stack[top-1],stack[top],p[i])<0&&top>=1) --top;  
  56.         stack[++top]=p[i];  
  57.     }  
  58. }  
  59.   
  60. bool Judge()  
  61. {  
  62.     for(int i=1;i<top;i++)  
  63.     {  
  64.         //判断凸包的一条边上是否至少有3点  
  65.         if((cross(stack[i-1],stack[i+1],stack[i]))!=0&&(cross(stack[i],stack[i+2],stack[i+1]))!=0)  
  66.             return false;  
  67.     }  
  68.     return true;  
  69. }  
  70.   
  71. int main()  
  72. {  
  73.     int t,n,i;  
  74.     scanf("%d",&t);  
  75.     while(t--)  
  76.     {  
  77.         scanf("%d",&n);  
  78.         for(i=0;i<n;i++)  
  79.             scanf("%lf%lf",&p[i].x,&p[i].y);  
  80.         if(n<6)  
  81.         {  
  82.             puts("NO");  
  83.             continue;  
  84.         }  
  85.         Graham(n);  
  86.         cout<<endl;  
  87.         for(i=0;i<n;i++)  
  88.           cout<<p[i].x<<" "<<p[i].y<<endl;  
  89.         cout<<endl;  
  90.         for(i=0;i<=top;i++)  
  91.           cout<<stack[i].x<<" "<<stack[i].y<<endl;  
  92.         if(Judge()) puts("YES");  
  93.         else        puts("NO");  
  94.     }  
  95.     return 0;  
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值