分析:给你一些点,这些点都在凸包的边或顶点上,问你凸包是不是稳定的,稳定凸包就是每条边上都至少有3个点,否则再多加一个点能形成更大的凸包,如果一条边上有>=3个点,这样在多加一个点,虽然也可能会形成更大的凸包,但一定不满足所有点都在边上,所以每条边都应该至少有3个点才稳定。用Graham扫描法求凸包时,会将除最左下角的点外其余的点排序,排序的规则是按照其余点和最左下角的连线和x轴所形成的角度排序的,角度小的排在前面,如果角度相同则将距离最左下角的点近的排在前面。这题已经已知所有点都在凸包上,所以排序之后点是这样的:除了最后一条边外,其余顶点都是按逆时针顺序依次连接的,所有只要把最后一条边的顶点的次序调换一下,调换完之后完全是按逆时针排序了,然后在判断每条边上是不是有>=3个点就行了,要注意的是,输入的n可能小于6,最小的稳定凸包的顶点数是6个,就是三角形每条边3个点,所以n<6直接输出NO。
# include <stdio.h>
# include <math.h>
# include <algorithm>
using namespace std;
struct point
{
int x,y;
}v[1005];
void Swap(point &a,point &b)
{
point t;
t=a; a=b; b=t;
}
double Cross(point a,point b,point c)
{
return (b.x-a.x)*(c.y-a.y)-(c.x-a.x)*(b.y-a.y);
}
double Dis(point a,point b)
{
return sqrt((double)((a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y)));
}
int Middle(point a,point b,point c)
{
if((b.x-a.x)*(b.x-c.x)>0||(b.y-a.y)*(b.y-c.y)>0)
return 0;
return 1;
}
int cmp(point a,point b)
{
double t=Cross(v[0],a,b);
if(t!=0)
return t>0?1:0;
return Dis(v[0],a)<Dis(v[0],b);
}
int main()
{
int i,j,n,min,t,f;
scanf("%d",&t);
while(t--)
{
scanf("%d",&n);
for(i=0,min=0;i<n;i++)
{
scanf("%d%d",&v[i].x,&v[i].y);
if(v[i].y<v[min].y||(v[i].y==v[min].y&&v[i].x<v[min].x))
min=i;
}
if(n<6)
{printf("NO\n");continue;}
Swap(v[0],v[min]);
sort(v+1,v+n,cmp);
for(i=0;i<n;i++)
if(Cross(v[i],v[i+1],v[i+2])<0)
break;
for(i=i+1,j=0;i+j<n-1-j;j++)
Swap(v[i+j],v[n-1-j]);
for(i=0,f=0;i<n;i++)
{
if(Cross(v[i],v[(i+1)%n],v[(i+2)%n])==0&&Middle(v[i],v[(i+1)%n],v[(i+2)%n])==1)
f=1;
else if(f==0)
break;
else
f=0;
}
if(i<n)
printf("NO\n");
else
printf("YES\n");
}
return 0;
}