半平面交

ACM笔记-4几何 专栏收录该内容
16 篇文章 0 订阅

求多边形核POJ3335
题意:一凸多边形球场,问是否在场上某处放一记分牌让所有边上观众看到


#include <bits/stdc++.h>
using namespace std;
#define exp 1e-10
struct node{double x;double y;};//定义点结构体
node point[105];//记录最开始的多边形
node q[105];    //临时保存新切割的多边形
node p[105];    //保存新切割出的多边形
int n,m;        //n原先点数,m新切出的多边形点数
double a,b,c;   //切边系数
void getline(node x,node y){//过XY两点获取直线ax+by+c==0系数
    a=y.y-x.y;
    b=x.x-y.x;
    c=y.x*x.y-x.x*y.y;
}//本函数由数学列式化简可得
node intersect(node x,node y){//获取交点:ax+by+c==0直线 和 点x和y所连直线
    double u=fabs(a*x.x+b*x.y+c);
    double v=fabs(a*y.x+b*y.y+c);
    node ans;
    ans.x=(x.x*v+y.x*u)/(u+v);
    ans.y=(x.y*v+y.y*u)/(u+v);
    return ans;
}//本函数由数学列式化简可得
void cut(){//用直线ax+by+c==0切割多边形,先用Q临时数组存本次切剩的边,最后再赋给P数组
    int cutm=0,i;//本轮切出的点初始化,I是循环系数而已
    for(i=1;i<=m;i++){//遍历一次全部点,每次取pi,pi-1,pi+1
        if(a*p[i].x+b*p[i].y+c>=0)q[++cutm]=p[i];
                //题目是顺时钟给点,一个点在直线右边则带入值就会大于等于0
                //在直线右边的意思就是这个点还在切割后的多边形内,将其保留
        else{   //该点不在多边形内
            if(a*p[i-1].x+b*p[i-1].y+c>0)q[++cutm]=intersect(p[i-1],p[i]);
            if(a*p[i+1].x+b*p[i+1].y+c>0)q[++cutm]=intersect(p[i+1],p[i]);
        }       //但是它和它相邻的点构成直线与ax+by+c==0所构成的交点可能在新切割出的多边形内
    }           //所以此时要保留
    for(i=1;i<=cutm;i++)p[i]=q[i];//把Q赋给P
    p[0]=q[cutm];   //末点记为第0个点
    p[cutm+1]=q[1]; //第一个点记到最后附加点
    m=cutm;         //更新切完后的新点数
}//因为每次取出pi,pi-1,pi+1所以有上面的赋值
void solve(){//求解
    for(int i=1;i<=n;i++)p[i]=point[i]; //复制
    p[n+1]=p[1];                        //把第一个点复制到第N+1个点
    p[0]=p[n];                          //把第N个点复制到第0个点
    m=n;                                //点数也初始复制
    for(int i=1;i<=n;i++){              //遍历
        getline(point[i],point[i+1]);   //根据point[i]和point[i+1]确定直线ax+by+c==0
        cut();                          //用直线ax+by+c==0切割多边形
    }
}
int main(){
    int cas;cin>>cas;//样例
    while(cas--){//样例自减
        scanf("%d",&n);//输入N
        for(int i=1;i<=n;i++)//遍历N个点,此题顺时针给出
            scanf("%lf%lf",&point[i].x,&point[i].y);//输入
        solve();//求解
        if(m==0)printf("NO\n");//切完的空间没有点就NO
        else printf("YES\n");//有就YES
    }
    return 0;
}
/*
2
4  0 0  0 1  1 1  1 0
YES
8  0 0  0 2  1 2  1 1  2 1  2 2  3 2  3 0
NO
*/

  • 0
    点赞
  • 0
    评论
  • 0
    收藏
  • 一键三连
    一键三连
  • 扫一扫,分享海报

相关推荐
©️2020 CSDN 皮肤主题: 黑客帝国 设计师:白松林 返回首页
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值