zoukankan      html  css  js  c++  java
  • 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");
            }
        }
    }
    
  • 相关阅读:
    海思HISI 3518EV200 AEC回音消除+ANR语音降噪(转)
    重磅消息 | 2020年最新全栈测试开发技能实战指南(第1期)
    推荐一款Python开源库,技术人必备的造数据神器!
    DevOps研发模式下「产品质量度量」方案实践
    自动化测试实战技巧:「用例失败重试机制」实现方案分享
    C#/VB.NET 在Word中添加条码、二维码
    Java 在PDF中绘制形状(基于Spire.Cloud.SDK for Java)
    Java 添加条码、二维码到Word文档
    Java 添加、下载、读取PDF附件信息(基于Spire.Cloud.SDK for Java)
    Java 添加、提取PDF中的图片
  • 原文地址:https://www.cnblogs.com/ucprer/p/13438282.html
Copyright © 2011-2022 走看看