题意:
题目链接1题目链接2
大概就是给你一些管道,求光从管口处射入最多能射多远
思路:
枚举拐点(上壁与下壁都算)作为直线(光束)上的两个点。然后判断这条直线和每一条线段((x_i, y_i)(x_i, y_i - 1))是否有交点。若无,则求出最远能到达的x。
注意事项:
丧心病狂的卡精度
不能直接跟0比较,而应是eps(好像本来就该这样吧。。。)
考虑精度误差,以及各种细节
code:
#include<cstdio>
#include<cmath>
#include<algorithm>
using namespace std;
const int N=30;
const double eps=1e-7;
struct point{double x,y;}e1[N],e2[N];
inline double lfabs(double x){if(x<-eps)x=-x;return x;}
bool operator==(point x,point y){return (lfabs(x.x-y.x)<eps)&&(lfabs(x.y-y.y)<eps);}
point operator-(point x,point y){return (point){x.x-y.x,x.y-y.y};}
double operator^(point x,point y){return x.x*y.y-x.y*y.x;}
double ans;
int n;
inline double inc(point p1,point p2,point u,point v)
{
return (((p1-u)^(p2-u))*((p1-v)^(p2-v)));//线段与直线判断交点情况
}
inline double slv_inc(point p1,point p2,point u,point v)
{
double s1=(u-p1)^(v-p1),s2=(v-p2)^(u-p2);
double anss=p2.x+(p1.x-p2.x)*s2/(s1+s2);
return anss;
}
int main()
{
while(7)
{
scanf("%d",&n);
if(!n) break;
for(int i=1;i<=n;++i)
{
scanf("%lf%lf",&e1[i].x,&e1[i].y);
e2[i]=e1[i]-(point){0.0,1.0};
}
bool pd=0;
int nn=n<<1;ans=e1[1].x;
for(int i=1;i<=nn&&(!pd);++i)
for(int j=i+1;j<=nn;++j)
{
point p1=i<=n?e1[i]:e2[i-n];
point p2=j<=n?e1[j]:e2[j-n];
if(p1.x>p2.x) swap(p1,p2);
bool flag=0;int pos=0;
for(int k=1;k<=n;++k)
{
if(e1[k]==p1||e1[k]==p2||e2[k]==p1||e2[k]==p2) continue;
if(e1[k].x-p2.x>eps){pos=k;break;}
if(inc(p1,p2,e1[k],e2[k])>eps){flag=1;break;}
}
if(flag) continue;
while(inc(p1,p2,e1[pos],e2[pos])<eps&&pos<=n)++pos;
if(pos>n||pos==0){puts("Through all the pipe.");pd=1;break;}
if(inc(p1,p2,e1[pos],e1[pos-1])<eps)ans=max(ans,slv_inc(p1,p2,e1[pos],e1[pos-1]));
if(inc(p1,p2,e2[pos],e2[pos-1])<eps)ans=max(ans,slv_inc(p1,p2,e2[pos],e2[pos-1]));
}
if(pd) continue;
printf("%.2f
",ans);
}
return 0;
}