poj 1279 Art Gallery(利用极角计算半平面交)

题意:给出n个点的坐标描述一个多边形画廊。在画廊平面上找到一片表面,从该区域能够看到画廊墙壁上的每一个点;

思路:将这片表面称为多边形的核。核中一点与多边形边界上任意一点的连线都在多边形内部。凸多边形的核为其本身,凹多边形的核为其内部的一部分或不存在;

将多边形的n个顶点转化为n条边的直线方程;逆时针用多边形的边剖分多边形所在平面,保留向里的部分,舍去向外的部分,剩下的即为核;

利用叉积公式计算核面积,即为所求面积;

#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
using namespace std;
const double epsi=1e-10;
const int maxn=2010;
const double pi=acos(-1.0);
inline int sign(const double &x){
    if(x>epsi) return 1;
    if(x<-epsi) return -1;
    return 0;
}
struct point{
    double x,y;
    point(double xx=0,double yy=0):x(xx),y(yy){}

    double operator ^(const point &op2) const{
        return x*op2.y-y*op2.x;
    }
};
struct line{
    double A,B,C;
    line(double aa=0,double bb=0,double cc=0):A(aa),B(bb),C(cc){}
    double f(const point &p) const{
        return A*p.x+B*p.y+C;  //计算p点代入直线方程后的解
    }
    double rang() const{
        return atan2(B,A);//直线的极角
    }
    double d() const{
        return C/(sqrt(A*A+B*B));//原点到直线的距离
    }
    point cross(const line &a)const{
        double xx=-(C*a.B-a.C*B)/(A*a.B-B*a.A);
        double yy=-(C*a.A-a.C*A)/(B*a.A-a.B*A);
        return point(xx,yy); //计算直线与直线a的交点
    }
};
line b[maxn],SL[maxn]; //当前核边的直线序列b[],多边形的边序列SL[]
point c[maxn],d[maxn]; //当前核的顶点序列c[],核的顶点序列d[]
int n;
double r;
point p[maxn];
int t[2];
point plane[2][maxn],q1,q2;

int cmp(line a,line b){  //极角作为第一关键字,原点至该直线的距离作为第二关键字比较直线a和直线b的大小
    if(sign(a.rang()-b.rang())!=0) return a.rang()<b.rang();
    else return a.d()<b.d();
}
inline int half_plane_cross(line *a,int n,point *pt){//利用极角计算和返回多边形a内最大凸多边形的顶点序列pt及其长度
   sort(a+1,a+n+1,cmp);
   int tn=1;
   for(int i=2;i<=n;i++){  //枚举多边形的相邻边,去除极角相同的相邻边或者A=B=0且C>0的边
    if(sign(a[i].rang()-a[i-1].rang())!=0) a[++tn]=a[i];
    if(sign(a[tn].A)==0&&sign(a[tn].B)==0)
        if(sign(a[tn].C)==1) tn--;//若C>0则移出a[];否则返回失败标志
        else return -1;
   }
   n=tn;  //a预处理后的长度
   int h=0,t=1; //队列的首尾指针初始化
   b[0]=a[1];
   b[1]=a[2];
   c[1]=b[1].cross(b[0]);  //直线1和直线2存入a,交点存入c
   for(int i=3;i<=n;i++){      //枚举直线3到直线n
      while(h<t&&sign(a[i].f(c[t]))<0) t--;  //若队列c非空且c的队尾交点代入直线i后的方程值为负,则队尾元素退出
      while(h<t&&sign(a[i].f(c[h+1]))<0) h++;//若队列c非空且c的队首交点代入直线i后的方程值为负,则队首元素退出
      b[++t]=a[i];               //直线i进入b的队尾
      c[t]=b[t].cross(b[t-1]);   //b队尾的两条直线交点进入c队尾
   }
   while(h<t&&sign(b[h].f(c[t]))<0) t--;
   while(h<t&&sign(b[t].f(c[h+1]))<0) h++;
   if(h+1>=t) return -1;   //若队列空,则失败返回
   pt[0]=b[h].cross(b[t]);  //b的首尾两条直线的交点作为凸多边形的首顶点
   for(int i=h;i<t;i++) pt[i-h+1]=c[i+1]; //凸多边形的其他顶点按c的顺序排列
   pt[t-h+1]=pt[0];  //凸多边形首尾相接
   return t-h+1;  //返回凸多边形的顶点数
}
int main()
{
   int x[maxn],y[maxn];  //多边形顶点坐标序列
   double ans=0;
   int n,m;       //多边形的顶点数为n,内部最大凸多边形的顶点数为m
   int test;
   scanf("%d",&test);
   while(test--){
        scanf("%d",&n);
        for(int i=1;i<=n;i++) scanf("%d%d",&x[i],&y[i]);
        x[n+1]=x[1];y[n+1]=y[1];  //首尾相接
        for(int i=1;i<=n;i++)    //计算每条边的直线方程,SL[]存储直线方程中的A,B,C
            SL[i]=line(-(y[i]-y[i+1]),-(x[i+1]-x[i]),-(x[i]*y[i+1]-x[i+1]*y[i]));
        m=half_plane_cross(SL,n,d);//利用极角计算多边形SL内最大凸多边形的顶点数m和顶点序列d
        ans=0;
        if(m==-1) printf("0.00\n");  //无凸多边形
        else{
            for(int i=0;i<m;i++) ans+=d[i]^d[i+1]; //采用叉积的方法计算最大凸多边形的面积
            printf("%.2f\n",ans/2);
        }
   }
   return 0;
}
时间: 2024-10-07 22:23:16

poj 1279 Art Gallery(利用极角计算半平面交)的相关文章

POJ 1279 Art Gallery 半平面交求多边形核

第一道半平面交,只会写N^2. 将每条边化作一个不等式,ax+by+c>0,所以要固定顺序,方便求解. 半平面交其实就是对一系列的不等式组进行求解可行解. 如果某点在直线右侧,说明那个点在区域内,否则出现在左边,就可能会有交点,将交点求出加入. //#pragma comment(linker, "/STACK:16777216") //for c++ Compiler #include <stdio.h> #include <iostream> #inc

poj 1279 -- Art Gallery (半平面交)

鏈接:http://poj.org/problem?id=1279 Art Gallery Time Limit: 1000MS   Memory Limit: 10000K Total Submissions: 5337   Accepted: 2277 Description The art galleries of the new and very futuristic building of the Center for Balkan Cooperation have the form

poj 2540 Hotter Colder(极角计算半平面交)

题意:玩家A初始时在(0,0)位置,每移动一次,玩家B提示与目标位置的距离远了.近了还是不变:在B回答后,确定目标位置可能存在的区域面积: 思路:以玩家A上一个位置与当前位置的连线做中垂线,将目标位置代入中垂线方程,得到对应不等式,根据回答的类型增加相应的半平面: 每回合后对当前半平面求交,输出交的面积: #include<cstdio> #include<cstdlib> #include<cstring> #include<iostream> #incl

POJ 1279 Art Gallery 半平面交+求多边形核的面积

裸的:半平面交+求多边形核的面积 Art Gallery Time Limit: 1000MS   Memory Limit: 10000K Total Submissions: 5735   Accepted: 2419 Description The art galleries of the new and very futuristic building of the Center for Balkan Cooperation have the form of polygons (not

POJ 1279 Art Gallery [半平面交]

Art Gallery Time Limit: 1000MS   Memory Limit: 10000K Total Submissions: 7324   Accepted: 2936 Description The art galleries of the new and very futuristic building of the Center for Balkan Cooperation have the form of polygons (not necessarily conve

POJ 1279 Art Gallery(半平面交求多边形核的面积)

题目链接 题意 : 求一个多边形的核的面积. 思路 : 半平面交求多边形的核,然后在求面积即可. #include <stdio.h> #include <string.h> #include <iostream> #include <math.h> using namespace std ; struct node { double x; double y ; } p[1510],temp[1510],newp[1510];//p是最开始的多边形的每个点,

POJ 1279 Art Gallery 半平面交 多边形的核

题意:求多边形的核的面积 套模板即可 #include <iostream> #include <cstdio> #include <cmath> #define eps 1e-18 using namespace std; const int MAXN = 1555; double a, b, c; int n, cnt; struct Point { double x, y; double operator ^(const Point &b) const {

POJ 1279 Art Gallery 多边形内核面积

题目大意:按顺序给出一个多边形的顶点,求这个多边形内核的面积.答案保留两位输出. 思路:半平面交.加边的时候要讨论一下第一个点和最后一个点,否则会wa的很惨. CODE: #include <cmath> #include <cstdio> #include <cstring> #include <iostream> #include <algorithm> #define MAX 1510 #define EPS 1e-8 #define DC

半平面交总结and模板

博客原文地址:http://blog.csdn.net/xuechelingxiao/article/details/40859973 这两天刷了POJ上几道半平面交,对半平面交有了初步的体会,感觉半平面交还是个挺实用的知识点. 半平面交主要是看的ZZY的国家队论文,他提出的是一种O(n×log(n))的排序增量法. 附论文地址: 算法合集之<半平面交的新算法及其实用价值>. POJ 3335 Rotating Scoreboard 题目大意: World finals 要开始了,比赛场地是一