题目大意:
原来有一个凸包,可是凸包的顶点不全告诉你,给你一些凸包的点,问用这些点能不能确定唯一的凸包。
原谅我渣.. T T 看了好久不懂题目什么鬼。。默默的搜了一下题解。
说的是,如果给的点扫一边构成当前的凸包,在扫描一边,看当前的凸包的每条边是否至少有三个点(包括这条边的端点),
因为没有三个点的话,就不能确定一个凸包,也行原来的凸包可以在这两个端点之外再加一点生出一条边~
很好理解的。
学了一下andrew算法,之前学的graham算法的模板是抄别人的感觉有点问题,还是用大白的好。
andrew,比较稳定,上下凸包扫一边,加上排序复杂度O(nlogn)
#include <algorithm>
#include <cstdio>
#include <cmath>
using namespace std;
struct pnode{
int x,y;
pnode(int xx=0,int yy=0):x(xx),y(yy){}
bool operator < (const pnode &b)const{
return x<b.x|| (x==b.x && y<b.y);
}
pnode operator - (const pnode &b)const{
return pnode(x-b.x,y-b.y);
}
int operator ^ (const pnode &b)const{
return x*b.y - y*b.x;
}
int operator *(const pnode &b)const{
return (x-b.x)*(x-b.y) + (y-b.y)*(y-b.y);
}
}p[1005];
int top , id[1005];
int cross(const pnode &p0,const pnode &p1,const pnode &p2){
return (p1-p0)^(p2-p0);
}
int andrew( int n )
{
sort(p,p+n);//坐标排序
top = 0;
for( int i = 0;i <n ;++i){
while( top>1 && cross(p[id[top-2]],p[id[top-1]],p[i])<=0 )//新点在左边
top--;
id[top++] = i;//将点的下标存入凸包
}//下凸包
int k = top;
for( int i = n-2;i>=0;i--){
while( top>k && cross(p[id[top-2]],p[id[top-1]],p[i])<=0)
top--;
id[top++] = i;
}
id[top] = id[0];
// if(n>1)
// top--;
return top;
}
bool judge( int top ,int n)
{
for( int i = 1;i<=top;++i )
{
bool f = false;
for( int j = 0 ; j<n;++j)
{
if( j==id[i-1] || j== id[i])continue;
if( cross(p[id[i-1]],p[id[i]],p[j])==0 )
{
f = true;break;
}
}
if( f== false)
return false;
}
return true;
}
int main()
{
int t,n;
scanf("%d",&t);
while(t--)
{
scanf("%d",&n);
for( int i= 0; i < n ; ++i )
scanf("%d %d",&p[i].x,&p[i].y);
if( n < 6 )
puts("NO");
else{
if( judge( andrew(n),n ))
puts("YES");
else puts("NO");
}
}
return 0;
}