poj1474 Video Surveillance

题意:求多边形的内核,即:在多边形内部找到某个点,使得从这个点能不受阻碍地看到多边形的所有位置.

只要能看到所有的边,就能看到所有的位置.那么如果我们能够在多边形的内部的点x看到某条边AB,这个点x一定在AB的”内侧”,如果按逆时针方向给出多边形的所有顶点并假设从A到B是逆时针行走,”内侧”就是指有向直线A->B的左侧,那么多边形的每条边对应了一个半平面,要想看见这条边必须保证x在这个半平面内.而且,只要对于每条边x都在这条边的左侧,那么x就是一个可行的点,能够看到整个多边形.

这个结论的必要性是显然的(如果x在某条边的右侧,那么一定看不到这条边)

充分性也可以证:假如存在某个点是x看不见的,那么从x向这个点连线,一定会穿过偶数条多边形的边(因为每穿过一条边就从多边形的内部走到外部或者从外部走到内部,而起点终点都在内部),那么这些边一定是有一半从边的左侧穿到右侧(即从内到外),一半从边的右侧穿到左侧(即从外到内).也就是说,如果存在一个x看不见的点,就一定存在一条多边形的边使得x在这条边的右侧,于是如果找不到一条多边形的边使得x在这条边的右侧,就不存在x看不见的点,于是这个结论具有充分性.

那么我们对n条边求一下半平面交,判段是否非空即可.注意这里结果是一个点或一个线段时也判作有解,我的方法是把多边形的每条边都向多边形外部沿法向量方向平移一点,这样点和线段就都变成了面积不为0的区域,避免了边界讨论.

#include<cstdio>
#include<cmath>
#include<algorithm>
using namespace std;
const int maxn=205;
const double eps=1e-8;
int cmp(double x){return x<-eps?-1:x>eps;}
struct point{
  double x,y;point(){}
  point(double a,double b){x=a;y=b;}
  void read(){scanf("%lf%lf",&x,&y);}
}P[maxn],p[maxn];
point operator +(point a,point b){return point(a.x+b.x,a.y+b.y);}
point operator -(point a,point b){return point(a.x-b.x,a.y-b.y);}
double cross(point a,point b){return a.x*b.y-a.y*b.x;}
struct line{
  point s,d;double arg;
  bool operator <(const line &B)const{return cmp(arg-B.arg)==-1;}
  line(){}
  line(point a,point b){s=a;d=b;arg=atan2(d.y,d.x);}
  void output(){
    printf("(%f,%f)+(%f,%f)\n",s.x,s.y,d.x,d.y);
  }
}L[maxn],q[maxn];
int n;
bool onleft(line A,point B){
  return cmp(cross(A.d,B-A.s))>0;
}
point mult(double t,point A){
  return point(t*A.x,t*A.y);
}
point intersect(line A,line B){
  double t=cross(B.d,A.s-B.s)/cross(A.d,B.d);
  return A.s+mult(t,A.d);
}
point rot(point A,double arg){
  return point(A.x*cos(arg)-A.y*sin(arg),A.x*sin(arg)+A.y*cos(arg));
}
int HPI(){
  sort(L,L+n);
  int head,tail;head=tail=0;q[tail++]=L[0];
  for(int i=1;i<n;++i){
    while(head+1<tail&&!onleft(L[i],p[tail-2]))tail--;
    while(head+1<tail&&!onleft(L[i],p[head]))  head++;
    q[tail++]=L[i];
    if(head+1<tail&&cmp(cross(q[tail-1].d,q[tail-2].d))==0){
      tail--;
      if(onleft(q[tail-1],L[i].s))q[tail-1]=L[i];
    }
    if(head+1<tail)p[tail-2]=intersect(q[tail-1],q[tail-2]);
  }
  while(head+1<tail&&!onleft(q[head],p[tail-2]))tail--;
  //  q[head].output();q[head+1].output();
  if(tail-head<=2)return 0;
  else return 1;
}
point normal(point A){return point(-A.y,A.x);}
point operator *(const double &t,const point &A){return point(A.x*t,A.y*t);}
int main(){
  int tests=0;
  while(scanf("%d",&n),n!=0){
    for(int i=0;i<n;++i)P[i].read();P[n]=P[0];
    for(int i=0;i<n;++i)L[i]=line(P[i]-eps*normal(P[i]-P[i+1]),P[i]-P[i+1]);
    if(HPI())printf("Floor #%d\nSurveillance is possible.\n",++tests);
    else printf("Floor #%d\nSurveillance is impossible.\n",++tests);
    printf("\n");
  }
  return 0;
}

 

posted @ 2017-02-24 18:26  liu_runda  阅读(313)  评论(0编辑  收藏  举报
偶然想到可以用这样的字体藏一点想说的话,可是并没有什么想说的. 现在有了:文化课好难