采用二分的方法,查找是否可见对面的篱笆。左边,右边两方收缩,采用点积叉积判断是否相交。
代码很丑.... 无视...
/*
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;
}