采用二分的方法,查找是否可见对面的篱笆。左边,右边两方收缩,采用点积叉积判断是否相交。
代码很丑.... 无视...
/* ID:bysen LANG:C++ PROG:fence4 */ #include<stdio.h> #include<algorithm> #include<cmath> #define MAXP 201 #define ERROR 1e-6 using namespace std; struct Point { double x,y; }point[MAXP],stand; struct Line { double x1,x2,y1,y2; int d1,d2; }line[MAXP]; int pointnum; int linenum; int sign(double); double xmult( Point,Point); bool cross(Point,Point,Point,Point); bool cross1(Point,Point,Point,Point); bool cross(Point,Point,int); void init(); bool legal(); void binarySeach(); void print(); int min( int a,int b ){ return a<b?a:b; } int max( int a,int b ){ return a>b?a:b; } bool cmp( Line a,Line b ) { if( a.d2==b.d2 ) return a.d1<b.d1; return a.d2<b.d2; } int main() { freopen( "fence4.in","r",stdin ); freopen( "fence4.out","w",stdout ); init(); if( !legal() ){ printf( "NOFENCE\n" ); return 0; } binarySeach(); sort( line,line+linenum,cmp ); print(); return 0; } void print() { printf( "%d\n",linenum ); for( int i=0;i<linenum;i++ ) printf( "%d %d %d %d\n",(int)line[i].x1,(int)line[i].y1,(int)line[i].x2,(int)line[i].y2 ); } void binarySeach() { linenum=0; for( int i=0;i<pointnum;i++ )//judge [i,i+1] line { Point l=point[i]; Point r=point[(i+1)%pointnum]; Point m; while(true)//夹逼 { if( fabs(r.x-l.x)<ERROR && fabs(r.y-l.y)<ERROR ) break; m.x=(l.x+r.x)/2; m.y=(l.y+r.y)/2; if( !cross(stand,m,i) ) { if( (fabs(m.x-l.x)<ERROR&&fabs(m.y-l.y)<ERROR) || (fabs(m.x-r.x)<ERROR&&fabs(m.y-r.y)<ERROR) ) break; line[linenum].x1=point[min(i,(i+1)%pointnum)].x; line[linenum].x2=point[max(i,(i+1)%pointnum)].x; line[linenum].y1=point[min(i,(i+1)%pointnum)].y; line[linenum].y2=point[max(i,(i+1)%pointnum)].y; line[linenum].d1=min(i,(i+1)%pointnum); line[linenum].d2=max(i,(i+1)%pointnum); linenum++; break; } if( cross(stand,l,i) ) { l.x=(l.x+m.x)/2; l.y=(l.y+m.y)/2; } if( cross(stand,r,(i+1)%pointnum) ) { r.x=(r.x+m.x)/2; r.y=(r.y+m.y)/2; } } } } void init() { scanf( "%d",&pointnum ); scanf( "%lf %lf",&stand.x,&stand.y ); for( int i=0;i<pointnum;i++ ) scanf( "%lf %lf",&point[i].x,&point[i].y ); } bool legal() { for( int i=0;i<pointnum;i++ )//use i and i+1 line for( int j=0;j<pointnum;j++ )//to cross [j,j+1]line if( cross( point[i],point[(i+1)%pointnum],point[j],point[(j+1)%pointnum] ) ) return false; return true; } int sign( double a ) { if( fabs(a)<ERROR ) return 0; return a>0?1:-1; } double xmult( Point p,Point q ){ return p.x*q.y-p.y*q.x; } bool cross( Point a,Point b,Point c,Point d ) { Point AB,CB,DB,CD,AD,BD; AB.x=a.x-b.x;AB.y=a.y-b.y; CB.x=c.x-b.x;CB.y=c.y-b.y; DB.x=d.x-b.x;DB.y=d.y-b.y; CD.x=c.x-d.x;CD.y=c.y-d.y; AD.x=a.x-d.x;AD.y=a.y-d.y; BD.x=b.x-d.x;BD.y=b.y-d.y; if( sign(xmult(AB,CB))*sign(xmult(AB,DB))<0 && sign(xmult(CD,AD))*sign(xmult(CD,BD))<0 ) return true; return false; } bool cross1( Point a,Point b,Point c,Point d ) { Point AB,CB,DB,CD,AD,BD; AB.x=a.x-b.x;AB.y=a.y-b.y; CB.x=c.x-b.x;CB.y=c.y-b.y; DB.x=d.x-b.x;DB.y=d.y-b.y; CD.x=c.x-d.x;CD.y=c.y-d.y; AD.x=a.x-d.x;AD.y=a.y-d.y; BD.x=b.x-d.x;BD.y=b.y-d.y; if( sign(xmult(AB,CB))*sign(xmult(AB,DB))<=0 && sign(xmult(CD,AD))*sign(xmult(CD,BD))<0 ) return true; return false; } bool cross( Point a,Point b,int at) { //a,b 不是边上的点, for( int i=0;i<pointnum;i++ ) { if( at==i ) continue; if( cross1(a,b,point[i],point[(i+1)%pointnum])==true ) return true; } return false; }