您的位置:首页 > 其它

poj 1228 Grandpa's Estate 凸包模板题

2014-07-19 15:38 513 查看
题意:一个由钉子加绳子围成的凸包农场。现在绳子和部分钉子缺失,问能否通过剩余的钉子确定农场有没有变小,没有变小输出YES,由可能变小输出NO。

题解:

由于原本的农场是凸包,所以剩余的点如果能确定农场,那么必定可以围成凸包,且凸包内部没有钉子。

由于要确定农场有没有变小,什么情况下能确定?当围成的凸包每条边上都有至少3个钉子(含端点)。why?因为如果只有两个钉子,那么可能存在一个消失的钉子位于这条边的外面,使得所围的农场变大,且凸包性质没变,这样就不能确定农场是否改变了;若有3个及以上的钉子,那么在边外加钉子的都会把凸包变成凹的,也就不符合农场的定义了。

总的来说,这题就是先用凸包模板找出凸包的端点。然后枚举所有的边,查看是否都有3个以上的钉子即可。

代码:

#include <cstdio>
#include <cstdlib>
#include <cmath>
#include <cstring>
#include <iostream>
#include <algorithm>
#include <map>
#include <set>
#include <queue>
using namespace std;
//基础点和向量运算
struct Point{
    int x,y;
    Point(int x=0,int y=0):x(x),y(y){}
};
typedef Point Vector;
Vector operator + (Vector A,Vector B){return Vector(A.x+B.x,A.y+B.y);}
Vector operator - (Vector A,Vector B){return Vector(A.x-B.x,A.y-B.y);}
Vector operator * (Vector A,double p){return Vector(A.x*p,A.y*p);}
Vector operator / (Vector A,double p){return Vector(A.x/p,A.y/p);}
bool operator <(const Point& a, const Point& b)
{
    return a.x<b.x||(a.x==b.x&&a.y<b.y);
}
int Cross(Vector A,Vector B){return A.x*B.y-A.y*B.x;}//叉积
int dis(Vector A,Vector B)//距离的平方
{
    return (A.x-B.x)*(A.x-B.x)+(A.y-B.y)*(A.y-B.y);
}

const int maxn=1e3+10;
int n;
Point p[maxn],ch[maxn];
int ConvexHull()//求凸包
{
    sort(p,p+n);
    int i,m=0,k;
    for(i=0;i<n;i++)
    {
        while(m>1&&Cross(ch[m-1]-ch[m-2],p[i]-ch[m-2])<=0)m--;
        ch[m++]=p[i];
    }
    k=m;
    for(i=n-2;i>=0;i--)
    {
        while(m>k&&Cross(ch[m-1]-ch[m-2],p[i]-ch[m-2])<=0)m--;
        ch[m++]=p[i];
    }
    if(n>1)m--;
    return m;
}
int judge(Point a,Point b)//判断凸包一条边上是否有3个以上的点(含端点)
{
    int i,num=0;
    for(i=0;i<n;i++)
    {
        if(Cross(a-p[i],p[i]-b)==0)num++;
    }
    if(num>=3)return 1;
    return 0;
}
int main()
{
    int T;
    scanf("%d",&T);
    while(T--)
    {
        scanf("%d",&n);
        int i,j,k,m;
        for(i=0;i<n;i++)
            scanf("%d%d",&p[i].x,&p[i].y);
        if(n<6){printf("NO\n");continue;}
        m=ConvexHull();
        //if(m!=n)printf("NO\n");
        //else
        {
            for(i=1;i<m;i++)
                if(!judge(ch[i],ch[i-1]))break;
            if(i<m||!judge(ch[0],ch[m-1]))printf("NO\n");
            else printf("YES\n");
        }
    }
    return 0;
}


内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: