<题目链接>
<转载于 >>> >
首先来了解什么是稳定的凸包。比如有4个点:
这四个点是某个凸包上的部分点,他们连起来后确实还是一个凸包。但是原始的凸包可能不是这样。
比如:
即这四个点构成的凸包不算做“稳定”的。我们发现,当凸包上存在一条边上的点只有端点两个点的时候,这个凸包不是稳定的,因为它可以在这条边外再引入一个点,构成一个新的凸包。但一旦一条边上存在三个点,那么不可能再找到一个点使它扩展成一个新的凸包,否则构成的新多边形将是凹的。
下面是一个典型的稳定凸包:
于是此题的做法就很明确了,就是在给出的点中,找到凸包,并且判断这个凸包是不是每条边至少有三个点。
1 #include <iostream> 2 #include <cstdio> 3 #include <cmath> 4 #include <cstring> 5 #include <algorithm> 6 #define eps 1e-8 7 using namespace std; 8 9 struct point{ 10 double x,y; 11 }; 12 point p[1010],stack[1010]; 13 int N,top; 14 double multi(point p1, point p2, point p3){ //向量(p1->p2)^(p1->p3) 15 return (p2.x - p1.x) * (p3.y - p1.y) - (p2.y - p1.y) * (p3.x - p1.x); 16 } 17 double dis(point a, point b){ 18 return sqrt((a.x - b.x) * (a.x - b.x) + (a.y - b.y) * (a.y - b.y)); 19 } 20 int cmp(const void *a, const void *b){ //按极角排序 21 point c = *(point *)a; 22 point d = *(point *)b; 23 double k = multi(p[0], c, d); 24 if(k < 0 || (!k && dis(c, p[0]) > dis(d, p[0]))) return 1; 25 return -1; 26 } 27 void Convex(){ //凸包的构建 Andrew算法 28 for(int i = 1; i < N; i++){ //先按x,y坐标排序,找到原点 29 point temp; 30 if(p[i].y < p[0].y || ( p[i].y == p[0].y && p[i].x < p[0].x)){ 31 temp = p[i]; 32 p[i] = p[0]; 33 p[0] = temp; 34 } 35 } 36 qsort(p + 1, N - 1, sizeof(p[0]), cmp); //再将除原点以外的点按极角排序 37 stack[0] = p[0]; //先将起始的两个点压入栈内,在进行后面的判断 38 stack[1] = p[1]; 39 top = 1; 40 for(int i = 2; i < N; i++){ 41 while(top >= 1 && multi(stack[top - 1], stack[top], p[i]) < 0)top--; //共线的点也压入凸包内; 42 top++; 43 stack[top] = p[i]; 44 } 45 } 46 bool judge(){ //这个函数是关键 47 for(int i=1;i<top;i++){ 48 if((multi(stack[i-1],stack[i+1],stack[i]))!=0&&(multi(stack[i],stack[i+2],stack[i+1]))!=0) //判断每条边是否有至少三个点,即判断i-1,i,i+1这三个点是否在一条直线上或者i,i+1,i+2是否在一条直线上 49 return false; 50 } 51 return true; 52 } 53 int main(){ 54 int t; 55 cin>>t; 56 while(t--){ 57 cin>>N; 58 for(int i=0;i<N;i++) 59 scanf("%lf%lf",&p[i].x,&p[i].y); 60 if(N<6)puts("NO"); 61 else{ 62 Convex(); 63 if(judge())puts("YES"); 64 else puts("NO"); 65 } 66 } 67 return 0; 68 }
2018-08-23