poj 1228 凸包
题意:给出一个去掉几个点后的凸包,判断是不是原始凸包。
看了大牛的思想后才知道:只要判断凸包的每个边上有三个顶点,就可以判断该凸包为原始凸包。
1、少于六个点不可能是原始凸包。
2、利用graham算法找出形成该凸包至少需要的顶点,存进数组res[]中,剩余的存进leave[]数组中。
3、遍历两个数组判断是否满足条件。
#include<iostream> #include<cstdio> using namespace std; #define MAX_INT 123456789 struct point { int x,y; }; point vertex[1000]; int res[1000],leave[1000],len; int angle(point p0,point p1,point p2)//p1,p2相对于p0的极角大小 { return (p1.y-p0.y)*(p2.x-p0.x)-(p2.y-p0.y)*(p1.x-p0.x); } int judge(point p0,point p1,point p2) { return (p2.y-p0.y)*(p1.x-p0.x)>(p1.y-p0.y)*(p2.x-p0.x); } int dist(point p1,point p2) { return (p2.x-p1.x)*(p2.x-p1.x)+(p2.y-p1.y)*(p2.y-p1.y); } int cmp(const void* a,const void *b) { int k; point p1,p2; p1=*(point*)a; p2=*(point*)b; k=angle(vertex[0],p1,p2); if(k==0) return dist(vertex[0],p1)>dist(vertex[0],p2); return k>0; } int graham(int m) { int i,top=0; res[0]=0; res[1]=1; len=0; qsort(vertex+1,m-1,sizeof(vertex[0]),cmp); vertex[m++]=vertex[0]; for(top=1,i=2;i<m;i++) { while(top && !judge(vertex[res[top-1]],vertex[res[top]],vertex[i]))//去掉不合适的点何在同一条直线上的点 leave[len++]=res[top--]; res[++top]=i; } return top; } int work(int m) { int count,i,j; m=graham(m); if(m<3) return 0; res[++m]=0; count=0; for(j=0;j<m;j++) { count=0; for(i=0;i<len;i++) { if(angle(vertex[res[j]],vertex[leave[i]],vertex[res[j+1]])==0)//找在同一条直线上的点 if(++count>=2) break; } if(count==0) return 0; } return 1; } int rePoint(int n) { int i,k; point p; p.x=MAX_INT; for(i=0;i<n;i++) if(vertex[i].x<p.x || (vertex[i].x==p.x && vertex[i].y<p.y)) { p=vertex[i]; k=i; } return k; } int main() { int i,m,n,k; point temp; scanf("%d",&n); while(n--) { scanf("%d",&m); for(i=0;i<m;i++) { scanf("%d%d",&vertex[i].x,&vertex[i].y); } if(m<6) { printf("NO\n"); continue; } k=rePoint(m); temp=vertex[k],vertex[k]=vertex[0],vertex[0]=temp; if(work(m)) printf("YES\n"); else printf("NO\n"); } return 0; }