[POJ3130]How I Mathematician Wonder What You Are!(半平面交)

本文介绍了一种判断多边形是否有核的方法,即通过求解一系列半平面交来找到可能存在的核区域。文章详细解释了半平面交算法的实现过程,并提供了完整的代码示例。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题目:

我是超链接

题意:

给出一个多边形,判断多边形是否有核

题解:

所谓多边形的核,简单来说就是有个人站在这个点,那么这个多边形内的每一个点这个人都能看见(光沿直线传播)
也就是说对于多边形的每一条边的一个半平面求交,可以交出来一个凸壳,这个点集中的点都满足要求
附图
这里写图片描述
这就是一道半平面交裸题了
诶等等我好像还不会半平面交

给出若干个半平面,求它们的交
也就是类似数学必修五的线性规划问题
半平面交的答案是一个凸壳

首先初始化的时候给它加上一个很大的框
然后每一次加入一条直线,将直线左边的点保留,并且计算出来这条直线和当前凸壳的交点加入,时间复杂度 O(n2)

void init()
{
    cnt=0;
    poly[++cnt]=Point(inf,inf);
    poly[++cnt]=Point(inf,-inf);
    poly[++cnt]=Point(-inf,-inf);
    poly[++cnt]=Point(-inf,inf);
}
void halfp(Point A,Point B)
{
    ncnt=0;
    Point C,D;
    for (int i=1;i<=cnt;++i)
    {
        C=poly[i%cnt+1];
        D=poly[(i+1)%cnt+1];
        if (dcmp(Cross(B-A,C-A))<=0)
            npoly[++ncnt]=C;
        if (insLS(A,B,C,D))
            npoly[++ncnt]=GLI(A,B-A,C,D-C);
    }
    cnt=ncnt;
    for (int i=1;i<=cnt;++i)
        poly[i]=npoly[i];
}

think less,time more
特别要注意判断insLS是直线与线段是否相交!
这里只是判断一个交点并不是重合,如果重合的话一定是两条平行直线,中间省去一个点没加也可以

代码:

#include <cstdio>
using namespace std;
const double INF=1e9;
const double eps=1e-9;
int dcmp(double x)
{
    if (x<=eps && x>=-eps) return 0;
    return (x>0)?1:-1;
}
struct po
{
    double x,y;
    po (double X=0,double Y=0){x=X;y=Y;}
}p[55],np[55],d[55];
int cnt,ncnt;
po operator -(po x,po y){return po(x.x-y.x,x.y-y.y);}
po operator +(po x,po y){return po(x.x+y.x,x.y+y.y);}
po operator *(po x,double y){return po(x.x*y,x.y*y);}
double cj(po x,po y){return x.x*y.y-x.y*y.x;}
void init()
{
    cnt=0;
    p[++cnt]=po(-INF,-INF);
    p[++cnt]=po(INF,-INF);
    p[++cnt]=po(INF,INF);
    p[++cnt]=po(-INF,INF);
}
bool have(po a,po b,po c,po d){return dcmp(cj(b-a,c-a))!=dcmp(cj(b-a,d-a));}
po jd(po a,po b,po c,po d){return a+b*(cj(c-a,d)/cj(b,d));}
void hp(po A,po B)
{
    ncnt=0;
    po C,D;
    for (int i=1;i<=cnt;i++)
    {
        C=p[i%cnt+1];
        D=p[(i+1)%cnt+1];
        if (dcmp(cj(B-A,C-A))>=0) np[++ncnt]=C;
        if (have(A,B,C,D)) np[++ncnt]=jd(A,B-A,C,D-C);
    }
    cnt=ncnt;
    for (int i=1;i<=cnt;i++) p[i]=np[i];
}
int main()
{
    int n;
    while (scanf("%d",&n)&&n)
    {
        double x,y;
        for (int i=1;i<=n;i++)
        {
            scanf("%lf%lf",&x,&y);
            d[i]=po(x,y);
        }
        init();
        for (int i=1;i<=n;i++)
          hp(d[i%n+1],d[(i+1)%n+1]);
        if (cnt) printf("1\n");else printf("0\n");
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值