题目链接: http://poj.org/problem?id=1228
这道题算是很好的一道凸包的题吧,做完后会加深对凸包的理解。
题意很关键。。。这英语看了好几遍才差不多看明白了。意思就是给你一堆点,这堆点本来就是某个凸包上的部分点,问你这堆点是否能确定唯一的凸包(大概这意思吧。。。)。后来搜了一下,发现这种凸包叫做稳定凸包。
首先来了解什么是稳定的凸包。比如有4个点:
这四个点是某个凸包上的部分点,他们连起来后确实还是一个凸包。但是原始的凸包可能不是这样。比如:
即这四个点构成的凸包不算做“稳定”的。我们发现,当凸包上存在一条边上的点只有端点两个点的时候,这个凸包不是稳定的,因为它可以在这条边外再引入一个点,构成一个新的凸包。但一旦一条边上存在三个点,那么不可能再找到一个点使它扩展成一个新的凸包,否则构成的新多边形将是凹的。
下面是一个典型的稳定凸包:
那么这道题的做法终于明确了。即求出给定这堆点的新的凸包,然后判断凸包上的每条边上是否至少有3个点存在,假如有一条边不符合条件,则输出NO。否则YES。
写的时候又遇到几个小问题了。。。一个是要修改一下凸包模板,大多数人的模板都是不包括共线点的。然后,如果输入的点数n小于6,那么直接输出NO。当然,也可以直接按极角排序进行比较。至于判断一条边上是否至少有三个点,我是这样做的,假设要判断的边i,那么判断边i和边i-1,边i和边i+1的夹角是否都为0(180)。
代码~:
1 //POJ--1228 2 #include <iostream> 3 #include <cstdio> 4 #include <cmath> 5 #include <cstring> 6 #include <algorithm> 7 #define eps 1e-8 8 using namespace std; 9 10 struct point 11 { 12 double x,y; 13 }; 14 point p[1010],stack[1010]; 15 int N,top; 16 17 double multi(point p1, point p2, point p3) 18 { 19 return (p2.x - p1.x) * (p3.y - p1.y) - (p2.y - p1.y) * (p3.x - p1.x); 20 } 21 22 double dis(point a, point b) 23 { 24 return sqrt((a.x - b.x) * (a.x - b.x) + (a.y - b.y) * (a.y - b.y)); 25 } 26 27 int cmp(const void *a, const void *b) 28 { 29 point c = *(point *)a; 30 point d = *(point *)b; 31 double k = multi(p[0], c, d); 32 if(k < 0 || (!k && dis(c, p[0]) > dis(d, p[0]))) return 1; 33 return -1; 34 } 35 36 void Convex() 37 { 38 for(int i = 1; i < N; i++) 39 { 40 point temp; 41 if(p[i].y < p[0].y || ( p[i].y == p[0].y && p[i].x < p[0].x)) 42 { 43 temp = p[i]; 44 p[i] = p[0]; 45 p[0] = temp; 46 } 47 } 48 qsort(p + 1, N - 1, sizeof(p[0]), cmp); 49 stack[0] = p[0]; 50 stack[1] = p[1]; 51 top = 1; 52 for(int i = 2; i < N; i++) 53 { 54 while(top >= 1 && multi(stack[top - 1], stack[top], p[i]) < 0) top--; //共线的点也压入凸包内; 55 top++; 56 stack[top] = p[i]; 57 } 58 } 59 60 bool judge() 61 { 62 for(int i=1;i<top;i++) 63 { 64 if((multi(stack[i-1],stack[i+1],stack[i]))!=0&&(multi(stack[i],stack[i+2],stack[i+1]))!=0) //判断每条边是否有至少三个点; 65 return false; 66 } 67 return true; 68 } 69 70 int main() 71 { 72 int t; 73 cin>>t; 74 while(t--) 75 { 76 cin>>N; 77 for(int i=0;i<N;i++) 78 scanf("%lf%lf",&p[i].x,&p[i].y); 79 if(N<6) puts("NO"); 80 else 81 { 82 Convex(); 83 if(judge()) puts("YES"); 84 else puts("NO"); 85 } 86 } 87 return 0; 88 }