[关键字]:计算几何
[题目大意]:给出N个点,先判断这些点能否构成一个边与边不相交的多边形,然后在判断站在给出点能看见哪几条边。
//================================================================================================================================
[分析]:第一问比较简单,只要判断规范相交就行了,利用叉积可以很容易的判断,祥见黑书。第二问可以用二分法解决,每次都找一条边的中点然后判断从给定点到中点是否和别的边相交,如果相交就二分判断能否看到左边或右边的部分,结束条件就是当前部分长度小于某个设定值。
[代码]:
View Code
/*
ID:procedure2
PROB:fence4
LANG:C++
*/
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<algorithm>
#include<cmath>
using namespace std;
const int MAXN=300;
const double JD=0.005;
struct node
{
double x,y;
}point[MAXN],eye;
struct rec
{
node a,b;
}edge[MAXN];
int N,ans=0;
bool v[MAXN],b[MAXN];
double cross(node a,node b,node c)
{
double x1=b.x-a.x,y1=b.y-a.y;
double x2=c.x-a.x,y2=c.y-a.y;
//printf("%0.lf %0.lf %0.lf %0.lf %0.lf %0.lf %0.lf\n",a.x,a.y,b.x,b.y,c.x,c.y,x1*y2-x2*y1);
return x1*y2-x2*y1;
}
int Cleck(rec A,rec B)
{
double t1=cross(A.a,A.b,B.a),t2=cross(A.a,A.b,B.b);
double t3=cross(B.a,B.b,A.a),t4=cross(B.a,B.b,A.b);
//printf("%lf %lf ****\n",t1,t2);
if (t1==0 || t2==0) return -1;
if (t1*t2<0 && t3*t4<0) return 1;
return 0;
}
bool Judge(const rec &mid)
{
for (int i=1;i<=N;i++)
if (!b[i])
if (Cleck(mid,edge[i])!=0) return 0;
return 1;
}
bool Watch(node A,node B)
{
if (sqrt((A.x-B.x)*(A.x-B.x)+(A.y-B.y)*(A.y-B.y))<JD) return 0;
rec mid;
bool flag=0;
mid.b.x=(A.x+B.x)/2;
mid.b.y=(B.y+A.y)/2;
mid.a.x=eye.x;
mid.a.y=eye.y;
//printf("%.0lf %.0lf %0.lf %0.lf\n",A.x,A.y,B.x,B.y);
if (Judge(mid)) return 1;
else
{
flag=Watch(A,mid.b);
if (!flag) flag=Watch(mid.b,B);
}
return flag;
}
int main()
{
freopen("fence4.in","r",stdin);
freopen("fence4.out","w",stdout);
scanf("%d",&N);
scanf("%lf%lf",&eye.x,&eye.y);
scanf("%lf%lf",&point[1].x,&point[1].y);
for (int i=2;i<=N;i++)
{
scanf("%lf%lf",&point[i].x,&point[i].y);
edge[i-1].a=point[i-1];
edge[i-1].b=point[i];
}
edge[N].a=point[1];
edge[N].b=point[N];
/*for (int i=1;i<=M;i++)
printf("%.0lf %.0lf %.0lf %.0lf\n",edge[i].a.x,edge[i].a.y,edge[i].b.x,edge[i].b.y);*/
//printf("%d %d\n",N,M);
for (int i=1;i<N;i++)
for (int j=i+1;j<=N;j++)
if (Cleck(edge[i],edge[j])==1) {printf("NOFENCE\n");return 0;}
memset(b,0,sizeof(b));
memset(v,0,sizeof(v));
for (int i=1;i<=N;i++)
{
if (cross(eye,edge[i].a,edge[i].b)==0) continue;
b[i]=1;
if (Watch(edge[i].a,edge[i].b)) ans++,v[i]=1;
b[i]=0;
}
printf("%d\n",ans);
if (v[N] && v[N-1]) swap(edge[N],edge[N-1]);
for (int i=1;i<=N;i++)
if (v[i]) printf("%0.lf %0.lf %0.lf %0.lf\n",edge[i].a.x,edge[i].a.y,edge[i].b.x,edge[i].b.y);
return 0;
}