一个凸包丢了一些点,剩下的点能否表示原凸包?
先看一下什么情况下可以表示原凸包:现有的凸包每边都有3个以上的点。这样丢掉的点必定也在凸包上,否则现有的点不再凸包上,与已知不符。
做法就是根据所给点再算一次凸包,判断每边是否有三个以上的点。
注意,n<6为NO,所给点为直线为NO。
常用的凸包模版有时会包含边上的点(比如起始三点共线),有的时候不会。借此机会整理下自己的凸包哈!
//Memory: 260K
//Time: 0MS
#include <iostream>
#include <algorithm>
#include <math.h>
using namespace std;
int top;
struct POINT
{
double x,y;
};POINT p[1005],ch[1005];
double dist(POINT a,POINT b)
{
return sqrt( (a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y) );
}
double multiply(POINT sp,POINT ep,POINT op)
{
return (sp.x-op.x)*(ep.y-op.y)-(ep.x-op.x)*(sp.y-op.y);
}
bool online(POINT s,POINT e,POINT p)
{
return( (multiply(e,p,s)==0) && ( ( (p.x-s.x)*(p.x-e.x)<=0 ) &&
( (p.y-s.y)*(p.y-e.y)<=0 ) ) );
}
bool ptcmp(POINT a,POINT b)
{
if(multiply(a,b,p[0])>0 || (multiply(a,b,p[0])==0 && (dist(a,p[0])<dist(b,p[0]))))
return 1;
return 0;
}
void graham(int n)
{
int i,k=0;
top=1;
POINT temp;
for(i=1;i<n;i++)
if(p[i].y<p[k].y || (p[i].y==p[k].y && p[i].x<p[k].x))
k=i;
temp=p[0];
p[0]=p[k];
p[k]=temp;
sort(p+1,p+n,ptcmp);
ch[0]=p[0];
ch[1]=p[1];
for(i=2;i<n;i++)
{
while(top>=1 && multiply(p[i],ch[top],ch[top-1])>=0)
top--;
ch[++top]=p[i];
}
ch[++top]=p[0];
}
int main()
{
int cas,n;
cin>>cas;
while(cas--)
{
cin>>n;
int i,j,flag=0,k=0;
for(i=0;i<n;i++)
cin>>p[i].x>>p[i].y;
graham(n);
for(i=1;i<top-1;i++)
{
flag=0;
for(j=0;j<=n;j++)
{
if(online(ch[i],ch[i-1],p[j]))
flag++;
if(flag>=3)
break;
}
if(flag<3)
k=1;
}
if(n<=5)
k=1;
else
{
for(i=2;i<n;i++)
if(multiply(p[i-2],p[i-1],p[i])!=0)
break;
if(n==i)
k=1;
}
if(k!=1)
cout<<"YES"<<endl;
else
cout<<"NO"<<endl;
}
return 0;
}