POJ 1584 判断凸包,点在多边形内外,点到直线最短距离

题意求给出一个多边形,问这个多边形是否是凸包,如果不是数出HOLE IS ILL-FORMED,如果是问一个棍子能否穿过,给出底面的圆心和半径。

分3步:

1、判断是否是凸多边形

2、判断点是否在多边形内部

3、判断点到各边的最小距离是否大于等于半径

由于输入是按照顺时针或者逆时针,所以只要判断相邻叉积同号就可以。。

#include <iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
using namespace std;
typedef double PointType;
struct point
{
    PointType x,y;
};
point data[160];
PointType Direction(point pi,point pj,point pk) //判断向量PiPj在向量PiPk的顺逆时针方向 +顺-逆0共线
{
    return (pj.x-pi. x)*(pk.y-pi.y)-(pk.x-pi.x)*(pj.y-pi.y);
}
PointType Dis(point a,point b)
{
    return sqrt((a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y));
}
int Graham_Scan(point *a,int numa)
{
    for(int i=0; i<numa; i++)
        if(Direction(a[i],a[(i+1)%numa],a[(i+2)%numa])*Direction(a[(i+1)%numa],a[(i+2)%numa],a[(i+3)%numa])<0)
            return 0;
    return 1;
}
bool On_Segment(point pi,point pj,point pk)
{
    if(pk.x>=min(pi.x,pj.x)&&pk.x<=max(pi.x,pj.x)&&pk.y>=min(pi.y,pj.y)&&pk.y<=max(pi.y,pj.y))
        return 1;
    return 0;
}
bool Segment_Intersect(point p1,point p2,point p3,point p4)
{
    PointType d1=Direction(p3,p4,p1),d2=Direction(p3,p4,p2),d3=Direction(p1,p2,p3),d4=Direction(p1,p2,p4);
    if(((d1>0&&d2<0)||(d1<0&&d2>0))&&((d3>0&&d4<0)||(d3<0&&d4>0)))
        return 1;
    if(d1==0&&On_Segment(p3,p4,p1))
        return 1;
    if(d2==0&&On_Segment(p3,p4,p2))
        return 1;
    if(d3==0&&On_Segment(p1,p2,p3))
        return 1;
    if(d4==0&&On_Segment(p1,p2,p4))
        return 1;
    return 0;
}
int Pandingdian(point a,int n,point *polygon)//1在多边形上 2在多边形外 0在多边形内
{
    point b;
    b.x=-9999999;
    b.y=a.y;
    int sum=0;
    polygon[n]=polygon[0];
    for(int i=1; i<=n; i++)
        if(polygon[i].y-polygon[i-1].y!=0&&Segment_Intersect(a,b,polygon[i],polygon[i-1]))
        {
            if(Direction(a,polygon[i],polygon[i-1])==0)
                return 1;
            sum++;
        }
    if(sum&1)
        return 0;
    return 2;
}
double DotProduct(point p0,point p1,point p2)
{
    return (p1.x-p0.x)*(p2.x-p0.x)+(p1.y-p0.y)*(p2.y-p0.y);
}
double MinDistance(point p0,point p1,point p2)
{
    double d=Dis(p1,p2);
    double u=DotProduct(p1,p0,p2)/(d*d);
    if(u<0)
        return Dis(p0,p1);
    else if(u>1)
        return Dis(p0,p2);
    else
    {
        point v;
        v.x=p1.x+u*(p2.x-p1.x);
        v.y=p1.y+u*(p2.y-p1.y);
        return Dis(p0,v);
    }
}
int main()
{
    point center;
    double bj;
    int n;
    while(~scanf("%d",&n),n>2)
    {
        scanf("%lf%lf%lf",&bj,¢er.x,¢er.y);
        for(int i=0; i<n; i++)
            scanf("%lf%lf",&data[i].x,&data[i].y);
        if(!Graham_Scan(data,n))
        {
            puts("HOLE IS ILL-FORMED");
            continue;
        }
        if(Pandingdian(center,n,data))
        {
            puts("PEG WILL NOT FIT");
            continue;
        }
        int f=1;
        for(int i=0; i<n; i++)
            if(MinDistance(center,data[i],data[(i+1)%n])<bj)
            {
                f=0;
                break;
            }
        if(f)
            puts("PEG WILL FIT");
        else
            puts("PEG WILL NOT FIT");
    }
    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值