POJ 1584(判断凸包+点和凸多边形关系+圆和凸多边形关系)

题意和做法转载自
優YoU http://user.qzone.qq.com/289065406/blog/1309142308
大致题意:
按照顺时针或逆时针方向输入一个n边形的顶点坐标集,先判断这个n边形是否为凸包。
再给定一个圆形(圆心坐标和半径),判断这个圆是否完全在n变形内部。

解题思路:
题意已经很直白了。。就是那个思路。。。
注意输入完顶点集后,要封闭多边形,方便后面枚举边。
封闭方法:
定义点集数组Vectex[1~n]记录n个顶点,再令Vectex[0]=Vectex[n],Vectex[n+1]=Vectex[1]

1、判断凸包:
由于点集已经按某个时针方向有序,因此可以先定义一个方向系数direction=0
两两枚举n边形的边,用叉积判断这两条边的转向(右螺旋或左螺旋),由于存在散点共线的情况,因此当且仅当叉积的值temp第一次不为0时,direction=temp,direction的值此后不再改变。(direction>0 则为右螺旋逆时针,direction<0则为左螺旋顺时针)
此后继续枚举剩下的边,只要判断direction*temp>=0即可,当存在一个direction*temp<0的边,说明这是凹多边形,就不是凸包了。
2、判断圆心与多边形的关系:
用环顾法:
设圆心为P,逐条枚举n边形的边AB,利用

计算PA和PB的夹角,最后求和得到的就是环顾角。
(1) 圆心在多边形内部时,环顾角=±360
(2) 圆心在多边形外部时,环顾角=0
(3) 圆心在多边形边上时(不包括顶点),环顾角=±180
(4) 圆心在多边形顶点时,环顾角为(0,360)之间的任意角,其实就是圆心所在的顶点的两条邻接边的夹角。
3、当圆心在圆内时,判断圆与多边形的关系
设圆心为P,逐条枚举n边形的边AB,利用得到△PAB的面积,
再根据公式S=0.5*|AB|*h,可以得到
枚举所有h与圆的半径R比对,只要所有的边都有R-h>=0,则说明圆在多边形内

#include <cstdio>
#include <iostream>
#include <cstring>
#include <cmath>
#include <algorithm>
#include <queue>
#include <map>
#include <stack>
#include <vector>
#define maxn 10010
#define maxe 100010
typedef long long ll;
using namespace std;
const double eps=1e-5;
const int inf=0x3f3f3f3f3f;
const double PI=2*asin(1);
typedef double T1;
struct Point
{
    T1 x,y;
    Point(){};
    bool discard;
    Point(T1 a,T1 b)
    {
        x=a,y=b;
        discard=false;
    }
    void input()
    {
        scanf("%lf%lf",&x,&y);
        discard=false;
    }
    Point operator +(Point a)
    {
        Point b(x+a.x,y+a.y);
        return b;
    }
    Point operator -(Point a)
    {
        Point b(x-a.x,y-a.y);
        return b;
    }
    T1 operator *(Point a)
    {
        return x*a.x+y*a.y;
    }
    T1 operator ^(Point a)
    {
        return x*a.y-y*a.x;
    }
    bool operator <(Point a)
    {
        return x<a.x;
    }
}o;
Point p[maxn];
Point ans[maxn];
double xmult(Point p0,Point p1,Point p2)
{
    return (p1-p0)^(p2-p0);
}
int sgn(double x)
{
    if(fabs(x) < eps)return 0;
    if(x < 0) return -1;
    return 1;
}
double dist(Point a,Point b)
{
    return sqrt((a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y));
}

//判断是不是凸多边形,输入的是逆时针或顺时针排好序的
bool judge(int n)
{
    double dir=0;
    double tmp;

    for(int i=0;i<n;i++)
    {
        int j=(i+1)%n;
        int k=(i-1+n)%n;
        tmp=xmult(p[i],p[k],p[j]);
        if(sgn(tmp)&&!sgn(dir))
        {
            dir=tmp;
        }
        if(sgn(dir)*sgn(tmp)<0)return false;
    }
    return true;
}
//判断点和多边形的关系
bool judge1(Point p1,int n)
{
    double tmp=0.0;
    int j;
    for(int i=0;i<n;i++)
    {
        j=(i+1)%n;
        double tmp1=dist(p1,p[i])*dist(p1,p[j]);
        if(sgn(tmp1)==0)return false;
        tmp1=(p1-p[i])*(p1-p[j])/tmp1;
        //cout<<tmp1<<endl;
        tmp=acos(tmp1)+tmp;
        //cout<<"tmp "<<tmp<<endl;
    }
    //cout<<tmp<<endl;

    if(sgn(tmp-2*PI)==0||sgn(tmp+2*PI)==0)return true;
    return false;
}
//点到线段的距离
double Dis_Line_Point(Point p0,Point a,Point b)
{
    if(sgn(xmult(p0,a,b))==0)
    {
        double x1=max(a.x,b.x);
        double x2=min(a.x,b.x);
        double y1=max(a.y,b.y);
        double y2=min(a.y,b.y);
        if(p0.x<=x1&&p0.x>=x2&&p0.y<=y1&&p0.y>=y2)
        {
            return 0;
        }
        else
        {
            return min(dist(p0,a),dist(p0,b));
        }
    }
    else
    {
        return fabs(xmult(p0,a,b)/dist(a,b));
    }
}

int main()
{
    int n;
    double r;
    Point round;
    //freopen("in.txt","r",stdin );
    while(scanf("%d",&n)==1)
    {
        if(n<3)break;
        scanf("%lf",&r);
        round.input();
        for(int i=0;i<n;i++)
        {
            p[i].input();
        }
        if(!judge(n))puts("HOLE IS ILL-FORMED");
        //判断
        else
        {
            if(!judge1(round,n))
            {
                puts("PEG WILL NOT FIT");
            }
            else
            {
                int flag=1;
                for(int i=0;i<n;i++)
                {
                    int j=(i+1)%n;
                    if(Dis_Line_Point(round,p[i],p[j])<r)
                    {
                        puts("PEG WILL NOT FIT");
                        flag=0;
                        break;
                    }
                }
                if(flag)puts("PEG WILL FIT");
            }
        }
    }
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值