[poj] 1228 Grandpa's Estate || 稳定凸包

原题

判断给出点形成的凸包是否稳定(点保证在凸包上)
稳定:无法形成一个新的凸包仍使这些点在凸包上(即每条边上的点至少有3个)


先求出凸包,然后判断每条边上的点是否大于2个

#include<cstdio>
#include<algorithm>
#include<cstring>
#define N 1010
using namespace std;
int t,n,m,per[N];
struct point
{
    int x,y;
    point() {}
    point(int _x,int _y) : x(_x),y(_y) {}
    point operator - (const point &b) const
	{
	    return point(b.x-x,b.y-y);
	}
    int operator * (const point &b) const
	{
	    return x*b.y-b.x*y;
	}
    bool operator < (const point &b) const
	{
	    if (x==b.x) return y<b.y;
	    return x<b.x;
	}
    int norm()
	{
	    return x*x+y*y;
	}
}p[N],q[N];

int dot(point a,point b)
{
    return a.x*b.x+a.y*b.y;
}

struct Line
{
    point a,b;
    int cnt;
    void init(point x,point y)
	{
	    a=x;
	    b=y;
	    cnt=0;
	}
    int online(point k)
	{
	    int d=(a-k)*(b-k);
	    if (d!=0) return 0;
	    if (dot(a-k,b-k)>0) return 0;
	    return 1;
	}
}line[N];

bool cmp(int i,int j)
{
    int d=(p[i]-p[1])*(p[j]-p[1]);
    if (d!=0) return d>0;
    return (p[i]-p[1]).norm()<(p[j]-p[1]).norm();
}

void Graham()
{
    int id=1;
    for (int i=2;i<=n;i++)
	if (p[i]<p[id]) id=i;
    if (id!=1) swap(p[1],p[id]);
    for (int i=1;i<=n;i++) per[i]=i;
    sort(per+2,per+n+1,cmp);
    q[++m]=p[1];
    for (int i=2,j;i<=n;i++)
    {
	j=per[i];
	while (m>=2 && (p[j]-q[m-1])*(q[m]-q[m-1])>=0)
	    m--;
	q[++m]=p[j];
    }
}

bool solve()
{
    q[m+1]=q[1];
    for (int i=1;i<=m;i++)
	line[i].init(q[i],q[i+1]);
    for (int i=1;i<=n;i++)
	for (int j=1;j<=m;j++)
	    line[j].cnt+=line[j].online(p[i]);
    for (int i=1;i<=m;i++)
	if (line[i].cnt<=2) return 1;
    return 0;
}

int main()
{
    scanf("%d",&t);
    while (t--)
    {
	scanf("%d",&n);
	m=0;
	for (int i=1;i<=n;i++)
	    scanf("%d%d",&p[i].x,&p[i].y);
	Graham();
	if (m<=2 || solve())
	    puts("NO");
	else puts("YES");
    }
    return 0;
}
原文地址:https://www.cnblogs.com/mrha/p/8168625.html