题目链接:点击打开链接
Time Limit: 1000MS | Memory Limit: 10000K | |
Total Submissions: 12222 | Accepted: 3433 |
Description
Input
Output
Sample Input
1 6 0 0 1 2 3 4 2 0 2 4 5 0
Sample Output
NO题意:这道题的题意相当难懂。 简单来说就是平面上有很多很多点,我们可以假设这些点的凸包是A。现在给你点集里面的部分点,并且跟你说这些点的最边上的点都是属于原凸包的(也就是说这部分点的凸包上的每一个点都是凸包A上的顶点) 现在问你,这个凸包会不会等于凸包A?
思路:看题意是不是很难懂? 什么叫唯一的凸包呢? 我们可以这么理解,对于一个现有凸包B,如果无论往哪里添加点,它形成的新的凸包A都是原来的凸包B,那么这个凸包B就是唯一的。(注意有一个条件是凸包B上的所有点必须在凸包A上)
简单在纸上画一下我们就能得出一个结论:只要每条边至少有第三个点,那么这个凸包就一定是原凸包A。因为如果一条边有三个点了,你再往里面加,根据凸包的性质,必然不会改变凸包结构。而如果你往外面加点,又必然取不到中间的点了,就不满足凸包B上所有点都在凸包A上这个性质了。又或者你往边上添加一个点,那么同理可得,也绝对不会改变凸包性质。
所以这道题其实就是让你求点集形成的凸包上每条边是不是至少有三个点。 是不是觉得很简单了?然而网上很多凸包模板是过不了的,刚开始做这道题,我直接复制了自己的凸包模板,然后简单判断一下每条边是不是有三个点,结果就是WA了。 输出过程后才发现自己的凸包模板不精确,很多多边形求出来的凸包是错的! 比如有一条边是ac,中间有一点b。凸包理应只有ac两点,却多了多余的b点!这就直接导致无法判断是否每条边有三个点或三个点以上! 所以自己又改了改原先的模板,试了几个特殊样例才得以AC。
代码:
#include <iostream> #include <cstdio> #include <cstring> #include <algorithm> #include <cmath> using namespace std; #define eps 1e-8 #define N 1100 struct Node { double x,y; }p[N],stack[N]; double mulit(Node a,Node b,Node c) { return (b.x-a.x)*(c.y-a.y)-(c.x-a.x)*(b.y-a.y); } double dist(Node a,Node b) { return (a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y); } int cmp(Node a,Node b) { if(mulit(p[0],a,b)>0) return 1; if(mulit(p[0],a,b)==0&&(dist(p[0],a)-dist(p[0],b))<eps) return 1; return 0; } int Graham(int n) { sort(p+1,p+n,cmp); stack[0]=p[0]; stack[1]=p[1]; stack[2]=p[2]; int l=3; while(l<n&&mulit(stack[0],stack[1],stack[2])==0) { stack[1]=stack[2]; stack[2]=p[l++]; } if(l==n) return -1; int top=2; for(int i=l;i<n;i++) { while(top>=1&&mulit(stack[top-1],p[i],stack[top])>=0) top--; stack[++top]=p[i]; } return top; } int Pointonline(Node a,Node b,Node c) { if(mulit(b,a,c)!=0) return 0; if(a.x<=max(b.x,c.x)&&a.y<=max(b.y,c.y)&&a.x>=min(b.x,c.x)&&a.y>=min(b.y,c.y)) return 1; return 0; } int main() { int T,n; scanf("%d",&T); while(T--) { scanf("%d",&n); for(int i=0;i<n;i++) scanf("%lf %lf",&p[i].x,&p[i].y); if(n<6) { printf("NO\n"); continue; } int k=0; for(int i=0;i<n;i++) { if(p[k].y>p[i].y||(p[k].y==p[i].y&&p[k].x>p[i].x)) k=i; } swap(p[0],p[k]); int top=Graham(n); if(top==-1) { printf("NO\n"); continue; } stack[top+1]=stack[0]; int flag; for(int i=0;i<=top;i++) { flag=0; for(int j=0;j<n;j++) { if(p[j].x==stack[i].x&&p[j].y==stack[i].y) continue; if(p[j].x==stack[i+1].x&&p[j].y==stack[i+1].y) continue; if(Pointonline(p[j],stack[i],stack[i+1])) flag=1; } if(!flag) { flag=-1; break; } } if(flag==-1) printf("NO\n"); else printf("YES\n"); } return 0; }