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\n");
     else{
        for(int i=0;i<m;i++) ans+=d[i]^d[i+1];
        printf("%.2f\n",ans/2);
     }
   }
   return 0;
}
时间: 2024-08-01 14:35:54

poj 2540 Hotter Colder(极角计算半平面交)的相关文章

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

题意:给出n个点的坐标描述一个多边形画廊.在画廊平面上找到一片表面,从该区域能够看到画廊墙壁上的每一个点: 思路:将这片表面称为多边形的核.核中一点与多边形边界上任意一点的连线都在多边形内部.凸多边形的核为其本身,凹多边形的核为其内部的一部分或不存在: 将多边形的n个顶点转化为n条边的直线方程:逆时针用多边形的边剖分多边形所在平面,保留向里的部分,舍去向外的部分,剩下的即为核: 利用叉积公式计算核面积,即为所求面积: #include<cstdio> #include<cstring&g

POJ 2540 Hotter Colder --半平面交

题意: 一个(0,0)到(10,10)的矩形,目标点不定,从(0,0)开始走,如果走到新一点是"Hotter",那么意思是离目标点近了,如果是"Colder“,那么就是远了,"Same"是相同.要你推测目标点的可能位置的面积. 解法:半平面交水题.从一个点到另一个点远了,说明目标点在两点之间连线的中垂线的离源点较近的一侧,即我们每次都可以得到一条直线来切割平面,要么切割左侧,要么切割右侧,要么都切,再求一个半平面交就可以得出可能面积了. 代码: #incl

POJ 2540 Hotter Colder

http://poj.org/problem?id=2540 题意:给你每次行走的路径,而且告诉你每次离一个点光源是远了还是近了,要求每次光源可能存在的位置的面积. 思路:如果出现"same",说明光源在中垂线上,面积为0,否则我们考虑远了或者近了,实际上就是在路径中两点连成直线的中垂线就是半平面直线,近了在这条直线的远侧,远了在这条直线的近侧. 1 #include<cstdio> 2 #include<iostream> 3 #include<cmat

poj 2451 Uyuw&#39;s Concert(半平面交)

Uyuw's Concert Time Limit: 6000MS   Memory Limit: 65536K Total Submissions: 8580   Accepted: 3227 Description Prince Remmarguts solved the CHESS puzzle successfully. As an award, Uyuw planned to hold a concert in a huge piazza named after its great d

POJ 2540 半平面交求可行区域面积

Hotter Colder Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 2343   Accepted: 981 Description The children's game Hotter Colder is played as follows. Player A leaves the room while player B hides an object somewhere in the room. Player

poj 3525 Most Distant Point from the Sea 半平面交 + 二分

题目来源: http://poj.org/problem?id=3525 分析: 题意:给定一个凸多边形,求多边形中距离边界最远的点到边界的距离. 思路 : 每次将凸多边形每条边往里平移d,判断是否存在核:二分d即可. 多边形边上的点(x , y)往里平移d 后的 坐标: s , e  为向量的 起点和终点, len 为起点和终点的距离, h 为平移的距离 x' = x + dx y' = y + dy dx = ( s.y - e.y ) / len * h ,( 原理 是 利用 三角形的相似

半平面交 模板 poj 3335 poj 3130 poj 1474 判断半平面交是否为空集

半平面交模板 const double pi= acos(-1.0); #define arc(x) (x / 180 * pi) const double EPS = 1e-8; const int Max_N = 105; struct Point{ double x,y; Point(){} Point(double x, double y):x(x),y(y){} Point operator - (Point p){ return Point(x- p.x , y - p.y ) ;

poj 3384 Feng Shui 半平面交的应用 求最多覆盖凸多边形的面积的两个圆 的圆心坐标

题目来源: http://poj.org/problem?id=3384 分析: 用半平面交将多边形的每条边一起向"内"推进R,得到新的多边形(半平面交),然后求多边形的最远两点. 代码如下: const double EPS = 1e-10; const int Max_N = 105 ; struct Point{ double x,y; Point(){} Point(double x, double y):x(x),y(y){} Point operator - (Point

POJ 1474 多边形的核(半平面交)

Video Surveillance Time Limit: 1000MS   Memory Limit: 10000K Total Submissions: 3145   Accepted: 1391 Description A friend of yours has taken the job of security officer at the Star-Buy Company, a famous depart- ment store. One of his tasks is to ins