POJ 1279 半平面交模板

POJ1279 半平面交模板

题意

以顺时针或逆时针顺序给定一个多边形,求该多边形核的面积

解法

半平面交要求边要按逆时针顺序,首先利用叉积判断给定点顺序为逆时针还是顺时针,然后按逆时针方向建边,最后跑半平面交算法,得到多边形的核。对核中相邻边求交点,利用叉积计算面积。

代码:

#include <cmath>
#include <vector>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <deque>
using namespace std;
const int maxn=2e3+5;
const double eps = 1e-8;
int sgn(double x) {
    if(fabs(x) < eps)
        return 0;
    if(x < 0)
        return -1;
    return 1;
}
struct Point {
    double x,y;
    Point() {}
    Point(double _x,double _y) {
        x = _x;
        y = _y;
    }
    Point operator -(const Point &b)const {
        return Point(x - b.x,y - b.y);
    }
    double operator ^(const Point &b)const {
        return x*b.y - y*b.x;
    }
    double operator *(const Point &b)const {
        return x*b.x + y*b.y;
    }
    Point Rotate(double rad){ //逆时针旋转
        return Point(x*cos(rad)-y*sin(rad),x*sin(rad)+y*cos(rad));
    }
    double angle(){
        return atan2(y,x);
    }
    double len(){
        return sqrt(x*x+y*y);
    }
};
double xmult(Point p0,Point p1,Point p2) { //p0p1 X p0p2
    return (p1-p0)^(p2-p0);
}
double getArea(Point a,Point b,Point c){
    return fabs(xmult(a,b,c))/2.0;
}
struct Line{
	Point s,t;
	double ang;
	Line(Point X=Point(),Point Y=Point()){
		s=X,t=Y,ang=(Y-X).angle();
	}
	double getangle(){
        return ang=(t-s).angle();
	}
};
Point getIntersectPoint(Line a, Line b) {
    double a1 = a.s.y - a.t.y, b1 = a.t.x - a.s.x, c1 = a.s.x * a.t.y - a.t.x * a.s.y;
    double a2 = b.s.y - b.t.y, b2 = b.t.x - b.s.x, c2 = b.s.x * b.t.y - b.t.x * b.s.y;
    return Point((c1*b2-c2*b1)/(a2*b1-a1*b2), (a2*c1-a1*c2)/(a1*b2-a2*b1));
}
Point p[maxn];//存顶点
Point pj[maxn];//存交点
bool judge(int n){//判断是否是逆时针的
    double ans=0;
    for(int i=1;i<=n-1;i++){
        ans+=xmult(p[0],p[i],p[i+1]);
    }
    return ans>0;
}
bool onRight(Line a,Line b,Line c){
    Point jiao=getIntersectPoint(b,c);
    if(xmult(a.s,a.t,jiao)<0){
        return 1;
    }
    else{
        return 0;
    }
}
bool cmpHL(Line a,Line b){
    double A=a.getangle(),B=b.getangle();
    if(sgn(A-B)==0){//平行的直线将最左边的放后面,便于去重
        return xmult(a.s,a.t,b.t)>=0;
    }
    else{
        return A<B;
    }
}
vector<Line> getHL(vector<Line> l){
    //去除角度相同的,保留最最左的
    sort(l.begin(),l.end(),cmpHL);
    int n=l.size();
    int cnt=0;
    for(int i=0;i<=n-2;i++){
        if(sgn(l[i].getangle()-l[i+1].getangle())==0){
            continue;
        }
        l[cnt++]=l[i];
    }
    l[cnt++]=l[n-1];

    deque<Line> que;
    for(int i=0;i<cnt;i++){
        while(que.size()>=2&&onRight(l[i],que[que.size()-1],que[que.size()-2])) que.pop_back();
        while(que.size()>=2&&onRight(l[i],que[0],que[1])) que.pop_front();
        que.push_back(l[i]);
    }
    while(que.size()>=3&&onRight(que[0],que[que.size()-1],que[que.size()-2])) que.pop_back();
    while(que.size()>=3&&onRight(que[que.size()-1],que[0],que[1])) que.pop_front();

    vector<Line> hl;
    for(int i=0;i<que.size();i++){
        hl.push_back(que[i]);
    }
    return hl;
}
int main () {
    int T;
    scanf("%d",&T);
    while(T--){
        int n;
        scanf("%d",&n);
        for(int i=1;i<=n;i++){
            scanf("%lf%lf",&p[i].x,&p[i].y);
        }
        vector<Line>l;
        if(judge(n)){//已经是逆时针
            for(int i=1;i<=n;i++){
                l.push_back(Line(p[i],p[i%n+1]));
            }
        }
        else{//是顺时针
            for(int i=1;i<=n;i++){
                l.push_back(Line(p[i%n+1],p[i]));
            }
        }
        vector<Line> hl=getHL(l);
        int lnum=hl.size();
        if(lnum>=3){
            for(int i=0;i<=lnum-1;i++){
                pj[i+1]=getIntersectPoint(hl[i],hl[(i+1)%lnum]);
            }
            double ans=0;
            for(int i=2;i<=lnum-1;i++){
                ans+=getArea(pj[1],pj[i],pj[i+1]);
            }
            printf("%.2f
",ans);
        }
        else{
            puts("0.00");
        }
    }
}
原文地址:https://www.cnblogs.com/ucprer/p/13438282.html