题目大意
在一段弯弯曲曲的管道内射一束光,光不会反射,求最远能射到哪里(求横坐标)
解题思路
A掉第一道较为复杂的计算几何题,爽。。
-
首先
最优的光线一定是经过上下各一个端点的
不然的话,假如我们把这束光进行平移,肯定能射得更远
这样就可以 O ( N 2 ) O(N^2) O(N2)来枚举光线了 -
接下来考虑判断光能射多远
-
这束光是“真实的光线”,即在之前不会被阻拦
-
这束光射出后,在哪里被阻拦
1. 与某条管道壁“规范”相交,即不相交于端点
2. 相交于端点,则有可能被阻拦,有可能穿过:
这只需要判断一下两端点相对与光线的位置就好了,具体见代码
-
#pragma GCC optimize(2)
#include<cstdio>
#include<algorithm>
#define gt() (p1==p2&&(p2=(p1=buf)+fread(buf,1,1000000,stdin),p1==p2)?EOF:*p1++)
#define Out() (fwrite(St,1,Top,stdout))
#define pt(ch) (Top<1000000?St[Top++]=ch:(Out(),St[(Top=0)++]=ch))
#define Tp double
#define db double
#define Vc Vector
using namespace std;
int Top;static char St[1000000],buf[1000000],*p1=buf,*p2=buf;
const int maxn=25;const db eps=1e-6,INF=-(1e100);
int n;db Ans;
struct Vc{
Tp x,y;
Vc operator -(const Vc B){return (Vc){x-B.x,y-B.y};}
Vc operator +(const Vc B){return (Vc){x+B.x,y+B.y};}
Vc operator *(const Tp p){return (Vc){x*p,y*p};}
}a[maxn],b[maxn],C,D;
Tp Cross(Vc A,Vc B){return A.x*B.y-A.y*B.x;}
Vc getpos(Vc P,Vc v,Vc Q,Vc w){//两直线交点
Vc u=P-Q;
db t=Cross(w,u)/Cross(v,w);
return (P+(v*t));
}
bool sameside(Vc A,Vc B){return (Cross(D-C,A-C)*Cross(D-C,B-C)>eps);}//叉积判断在直线同侧
Tp read(){
int ret=0;bool f=0;char ch=gt();
while(ch<'0'||ch>'9') f|=(ch=='-'),ch=gt();
while(ch>='0'&&ch<='9') ret=ret*10+ch-'0',ch=gt();
db res=ret;
if(ch=='.'){db d=1;ch=gt();while(ch>='0'&&ch<='9') res+=(ch-'0')/(d*=10),ch=gt();}
return f?-res:res;
}
void write(int x){if(x>9) write(x/10);pt(x%10+'0');}
bool check(Vc A,Vc B){return (Cross(C-A,D-A)*Cross(C-B,D-B)<-eps);}//规范相交
bool Across(Vc A,Vc B){return (Cross(C-A,D-A)*Cross(C-B,D-B)<eps);}//相交
int main(){
#ifdef hhh
freopen("data.in","r",stdin);
freopen("data.out","w",stdout);
#endif
for(n=read();n;n=read()){
for(int i=1;i<=n;i++) b[i]=a[i]=(Vc){read(),read()},b[i].y-=1.0;
bool flg=1;Ans=INF;
for(int i=1;i<=n&&flg;i++)
for(int j=1,k;j<=n;j++)if(i!=j){
C=a[i],D=b[j];
for(k=1;k<n;k++)
if(check(a[k],a[k+1])||check(b[k],b[k+1])||sameside(a[k+1],b[k+1])||sameside(a[k],b[k])) break;
if(k==n){flg=0;break;}
if(k>=i&&k>=j){//真实直线
db tep_a=INF,tep_b=INF;
if(Across(a[k],a[k+1])) tep_a=getpos(a[k],a[k+1]-a[k],C,D-C).x;
if(Across(b[k],b[k+1])) tep_b=getpos(b[k],b[k+1]-b[k],C,D-C).x;
if(tep_a>Ans) Ans=tep_a;if(tep_b>Ans) Ans=tep_b;
}
}
if(!flg) puts("Through all the pipe.");
else printf("%.2f\n",Ans);
}
return 0;
}