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


    题意:玩家A初始时在(0,0)位置,每移动一次,玩家B提示与目标位置的距离远了、近了还是不变;在B回答后,确定目标位置可能存在的区域面积;

    思路:以玩家A上一个位置与当前位置的连线做中垂线,将目标位置代入中垂线方程,得到对应不等式,根据回答的类型增加相应的半平面;

            每回合后对当前半平面求交,输出交的面积;

    #include<cstdio>
    #include<cstdlib>
    #include<cstring>
    #include<iostream>
    #include<string>
    #include<cmath>
    #include<algorithm>
    using namespace std;
    const double epsi=1e-10;
    const int maxn=20100;
    const double pi=acos(-1.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],S[maxn]; //当前核边的直线序列b[],多边形的边序列SL[],s[]暂存半平面
    point c[maxn],d[maxn]; //当前核的顶点序列c[],核的顶点序列d[]
    int n;
    inline int sign(const double &x){
        if(x>epsi) return 1;
        if(x<-epsi) return -1;
        return 0;
    }
    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()
    {
       double x1,x2,y1,y2,ans=0;
       int m;
       n=0;
       SL[++n]=line(0,1,0);
       SL[++n]=line(1,0,0);
       SL[++n]=line(0,-1,10);
       SL[++n]=line(-1,0,10);//初始时区域[0,10]*[0,10]作为4个半平面
       double px=0,py=0,nx,ny;//上一步(px,py),当前(nx,ny)
       string c;//提示字符串
       char s;
       while(scanf("%lf%lf",&nx,&ny)!=EOF){
         cin>>c;
         if(c[0]=='C')  //根据提示,增添相应的平面
            SL[++n]=line(-2*(nx-px),-2*(ny-py),-(px*px+py*py-nx*nx-ny*ny));
         else if(c[0]=='H')
            SL[++n]=line(2*(nx-px),2*(ny-py),(px*px+py*py-nx*nx-ny*ny));
         else
            SL[++n]=line(-2*(nx-px),-2*(ny-py),-(px*px+py*py-nx*nx-ny*ny)),
            SL[++n]=line(2*(nx-px),2*(ny-py),(px*px+py*py-nx*nx-ny*ny));
         px=nx,py=ny;
         ans=0;
         //for(int i=1;i<=n;i++) S[i]=SL[i];
         m=half_plane_cross(SL,n,d);
         if(m==-1) printf("0.00
    ");
         else{
            for(int i=0;i<m;i++) ans+=d[i]^d[i+1];
            printf("%.2f
    ",ans/2);
         }
       }
       return 0;
    }
  • 相关阅读:
    修改 markdown 二级标题的编号 自动编号 autoNumber.js nodejs
    摆脱鼠标系列 百度搜索 火柴 快捷键 Ctrl两次
    代码片段管理软件 发现 utools 这个工具还行 windows软件
    java 携带session 前台传递cookie 跨域解决方案 vue + java
    用nodejs 调用 博客园 MetaWeblog,获取自己全部列表标题
    利用 油猴脚本 每日填日志
    Vue.prototype.$app = this vscode ctrl 点击 不跳转
    vscode 切换主侧栏可见性 原Ctrl+B 我改为了 Alt+P
    vscode 快速切换窗口 快捷键 设置成 Alt + Q 了
    snipaste 截屏工具快捷键 alt + A 还有 Ctrl + Shift + A
  • 原文地址:https://www.cnblogs.com/dashuzhilin/p/4556571.html
Copyright © 2020-2023  润新知