poj3335

题意:判断一个多边形内是否存在核。

分析:半平面交的模板题。用半平面交来求多边形的核可以用在线算法还实现,这个算法把问题分解成凸多边形与半平面相交(这个半平面的分界线就是题目中的多边形的每一条边)。求凸多边形与半平面的交集的做法是,先定义一个空的多边形,枚举多边形的点,若点在半平面内就加到这里定义的多边形的点集里,若与多边形的边相交就计算交点,再把交点也放到点集里。

 

#include <cstdio>
#define vector point
struct point
{
    double x,y;
    point(double xx = 0,double yy = 0)
    {
        x = xx;
        y = yy;
    }
    point operator - (const point& s)
    {
        return point(x - s.x, y - s.y);
    }
    point operator + (const point& s)
    {
        return point(x + s.x,y + s.y);
    }
};
struct polygon
{
    point p[100];
    int size;
};
struct line
{
    point first,second;
    line(point p1 = point(),point p2 = point())
    {
        first = p1;
        second = p2;
    }
};

double cross_product(vector v1,vector v2)
{
    return v1.x * v2.y - v1.y * v2.x;
}
//点积
double dot_product(vector v1,vector v2)
{
    return v1.x * v2.x + v1.y * v2.y;
}

//求两直线交点
point line_intersection(line ln1,line ln2)
{
    double a1,b1,c1,a2,b2,c2;
    a1 = ln1.first.y - ln1.second.y;
    b1 = ln1.second.x - ln1.first.x;
    c1 = ln1.first.x * ln1.second.y - ln1.second.x * ln1.first.y;
    a2 = ln2.first.y - ln2.second.y;
    b2 = ln2.second.x - ln2.first.x;
    c2 = ln2.first.x * ln2.second.y - ln2.second.x * ln2.first.y;
    double d = a1 * b2 - a2 * b1;
    return point((b1 * c2 - b2 * c1) / d,(c1 * a2 - c2 * a1) / d);
}

//一个多边形与一个半平面的交集
polygon hpi(polygon& poly,line& ln)
{
    int m = 0;
    polygon hull;
    point p1 = ln.first,p2 = ln.second;
    //穷举多边形的所有点,判断是否在半平面上
    //如果凸多边形hull与直线ln有交点就求交点
    for(int i = 0;i < poly.size;i++)
    {
        double c = cross_product(p2 - p1,poly.p[i] - p1);
        double d = cross_product(p2 - p1,poly.p[(i + 1) % poly.size] - p1);
        //点poly.p[i]在半平面上
        if(c >= 0)
            hull.p[m++] = poly.p[i];
        //有交点
        if(c * d < 0)
        {
            hull.p[m++] = line_intersection(line(poly.p[(i + 1) % poly.size],poly.p[i]),ln);
            //printf("intersect = ( %g, %g)\n",hull.p[m - 1].x,hull.p[m - 1].y);
        }
    }
    //printf("\n\n");
    hull.size = m;
    return hull;
}

//poly的顶点顺时针
bool polygon_kernel(polygon& poly,polygon& knl)
{
    //初始化核为无限大
    knl.p[0] = point(-1e18,-1e18);
    knl.p[1] = point(1e18,-1e18);
    knl.p[2] = point(1e18,1e18);
    knl.p[3] = point(-1e18,1e18);
    knl.size = 4;
    line ln;
    point pre = poly.p[0];
    for(int i = 1;i <= poly.size;i++)
    {
        ln.first = poly.p[i % poly.size];
        ln.second = poly.p[i - 1];
        knl = hpi(knl,ln);
        if(knl.size == 0)
            return false;
    }
    return true;
}


int main()
{
    int t,n,s;
    polygon poly,knl;
    scanf("%d",&t);
    while(t--)
    {
        scanf("%d",&n);
        for(int i = 0;i < n;i++)
            scanf("%lf%lf",&poly.p[i].x,&poly.p[i].y);
        poly.size = n;
        if(polygon_kernel(poly,knl))
            printf("YES\n");
        else
            printf("NO\n");
    }
    return 0;
}

 

转载于:https://www.cnblogs.com/ZShogg/archive/2013/05/07/3064019.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值