刚开始试着连一下,对于没有任何遮挡的线段,连接观察点和他的中点,如果没有阻挡,那么肯定就能看见啦
对于有遮挡的呢,我们可以试一下连接遮挡他的遮挡线段的端点,发现好像有点意思,如果射线能跟他严格相交,并且射线在另一面没有被夹住的话,就是可以看见的
于是有了算法,连接端点和所有中点。怎么编程呢,发现可以设一个mr表示如果射线右边有端点交于射线的最小距离,ml同理,mm表示于射线严格相交的最近的一个点,我们发现,如果mm不存在,或者射线被2端夹住了(ml<mm&&mr<mm)就不行了。。有木有特殊情况呢。。木有,都被排除了。而且这样mm好像也把中点问题解决了。
(嘛。。。相当于你通过一个边缘刚好看见一个物体,你怎么才算能看见呢,视角可以往那边移一点,但是如果那边又有一个边缘夹住了视角,就只是一条缝,当然看不见了)
代码就可以这样写(以下代码是参考。自认为写的很恶心)
# include <cstdio> # include <iostream> # include <algorithm> # include <cfloat> # include <cmath> using namespace std; int n,cansee[300]; double ox,oy,x[300],y[300],eps = 1e-6; struct Point{ double x,y; Point (double x,double y):x(x),y(y) {} }; int online(Point p1,Point p2,Point p3) { return (p1.x<max(p2.x,p3.x)&&p1.x>min(p2.x,p3.x)&&p1.y>min(p2.y,p3.y)&&p1.y<max(p2.y,p3.y)); } double f(Point p1,Point p2,Point p3) { return (p3.x-p2.x)*(p1.y-p2.y) - (p3.y-p2.y)*(p1.x-p2.x); } int ff(Point p1,Point p2,Point p3,Point p4) { double d1 = f(p1,p3,p4); double d2 = f(p2,p3,p4); double d3 = f(p3,p1,p2); double d4 = f(p4,p1,p2); if (d1*d2<0&&d3*d4<0) return 1; if (fabs(d1)<eps&&online(p1,p3,p4)) return 1; if (fabs(d2)<eps&&online(p2,p3,p4)) return 1; if (fabs(d3)<eps&&online(p3,p1,p2)) return 1; if (fabs(d4)<eps&&online(p4,p1,p2)) return 1; return 0; } double dist(double a1,double b1) { return sqrt((ox-a1)*(ox-a1)+(oy-b1)*(oy-b1)); } int judge(double ix,double iy,double x1,double y1,double xp,double yp) { if ((((ix-ox)*(x1)+(iy-oy)*(y1))/(dist(ix,iy)*dist(xp,yp))>eps)) return 1; return 0; } int ifcansee(double xp,double yp) { double mr=DBL_MAX,ml=DBL_MAX,mm=DBL_MAX; Point p1(ox,oy),p2(xp,yp); int res; double x1 = xp-ox,y1 = yp-oy; double a1 = y1,b1 = -x1,c1 = a1*ox+b1*oy; for (int i=0;i<n;++i) { Point p3(x[i],y[i]),p4(x[i+1],y[i+1]); double x2 = x[i+1]-x[i],y2 = y[i+1]-y[i]; double a2 = y2,b2 = -x2,c2 = a2*x[i]+b2*y[i]; double cross = a1*b2-a2*b1; if (fabs(cross)<eps) continue; double d1 = f(p3,p1,p2),d2 = f(p4,p1,p2); if (d1*d2<0) { double ix = (b2*c1-b1*c2)/cross,iy = (a1*c2-a2*c1)/cross; if (judge(ix,iy,x1,y1,xp,yp)) { double len = dist(ix,iy); if (len<mm) { mm = len; res = i+1; } } } if (fabs(d1)<eps&&judge(p3.x,p3.y,x1,y1,xp,yp)&&d2>0) mr = min(mr,dist(p3.x,p3.y)); if (fabs(d2)<eps&&judge(p4.x,p4.y,x1,y1,xp,yp)&&d1>0) mr = min(mr,dist(p4.x,p4.y)); if (fabs(d2)<eps&&judge(p4.x,p4.y,x1,y1,xp,yp)&&d1<0) ml = min(ml,dist(p4.x,p4.y)); if (fabs(d1)<eps&&judge(p3.x,p3.y,x1,y1,xp,yp)&&d2<0) ml = min(ml,dist(p3.x,p3.y)); } if (mm==DBL_MAX||(mr<mm&&ml<mm)) return -1; return res; } int main() { freopen("fence4.in","r",stdin); freopen("fence4.out","w",stdout); int i,j,t,ans=0; cin>>n>>ox>>oy; for (i=0;i<n;++i) cin>>x[i]>>y[i]; x[n] = x[0]; y[n] = y[0]; for (i=0;i<n;++i) for (j=0;j<n;++j) { if (j==i) continue; Point P1(x[i],y[i]); Point P2(x[i+1],y[i+1]); Point P3(x[j],y[j]); Point P4(x[j+1],y[j+1]); if (ff(P1,P2,P3,P4)) { cout<<"NOFENCE"<<endl; return 0; } } for (i=0;i<n;++i) { t = ifcansee(x[i],y[i]); if (t!=-1) cansee[t] = 1; t = ifcansee((x[i]+x[i+1])/2.0,(y[i]+y[i+1])/2.0); if (t!=-1) cansee[t] = 1; } for (i=1;i<=n;++i) if (cansee[i]) ans++; cout<<ans<<endl; for (i=1;i<n-1;++i) if (cansee[i]) cout<<x[i-1]<<" "<<y[i-1]<<" "<<x[i]<<" "<<y[i]<<endl; if (cansee[n]) cout<<x[0]<<" "<<y[0]<<" "<<x[n-1]<<" "<<y[n-1]<<endl; if (cansee[n-1]) cout<<x[n-2]<<" "<<y[n-2]<<" "<<x[n-1]<<" "<<y[n-1]<<endl; return 0; }