题目给出管道上半部分各个拐点处的坐标(x,y),管道宽度为1,对应下半部分各个拐点处的坐标是(x,y-1),求直线穿过水管相交处的横坐标的最大值。
直线与每个拐点上下连线的线段若有交点则表示穿过管道,如果不能穿过,在第k节管道处无法穿过,则需要计算最大坐标x,即分别计算与第k-1节管子的上、下管壁相交, 求得最大坐标。
#include<cstdio>
#include<cmath>
#include<map>
#include<cstring>
#include<algorithm>
using namespace std;
const double eps=1e-8;
int sgn(double x){
if(fabs(x)<eps)
return 0;
if(x<0)
return -1;
else return 1;
}
struct point{
double x,y;
point(){}
point(double sx,double sy):x(sx),y(sy){}
point operator -(const point &w)const{ //相减
return point(x-w.x,y-w.y);
}
double operator ^(const point &w)const{ //叉积
return x*w.y-y*w.x;
}
double operator *(const point &w)const{ //点积
return x*w.x+y*w.y;
}
}p[100];
struct line{
point st,ed;
line(){}
line(point sa,point sb):st(sa),ed(sb){}
pair<int,point>operator &(const line &w)const{ //两直线关系
point res=st;
if(sgn((st-ed)^(w.st-w.ed))==0){
if(sgn((st-w.ed)^(w.st-w.ed))==0)
return make_pair(0,res); //重合
else
return make_pair(1,res); //平行
}
double tmp=((st-w.st)^(w.st-w.ed))/((st-ed)^(w.st-w.ed));
res.x+=(ed.x-st.x)*tmp;
res.y+=(ed.y-st.y)*tmp;
return make_pair(2,res); //相交
}
}l[100],g[100];
bool isCross(line a,line b){ //直线和直线是否相交
return
sgn((b.st-a.ed)^(a.st-a.ed))*sgn((b.ed-a.ed)^(a.st-a.ed))<=0;
}
int main(){
int n;
while(~scanf("%d",&n),n){
int pnt=0;
int lnt=0,gnt=0;
for(int i=0;i<n;i++){
scanf("%lf%lf",&p[pnt].x,&p[pnt].y);
p[pnt+1].x=p[pnt].x;
p[pnt+1].y=p[pnt].y-1.0;
if(pnt!=0){
l[lnt++]=line(p[pnt-2],p[pnt]);
l[lnt++]=line(p[pnt-1],p[pnt+1]);
}
g[gnt++]=line(p[pnt],p[pnt+1]);
pnt+=2;
}
bool flag=false;
double ans=p[0].x;
for(int i=0;i<pnt&&!flag;i++)
for(int j=i+1;j<pnt;j++){
if(i%2==0&&j==i+1)
continue;
line mp=line(p[i],p[j]);
int k;
for(k=0;k<gnt;k++)
if(!isCross(mp,g[k])){
if(k!=0){
ans=max(ans,(mp&l[2*(k-1)]).second.x);
ans=max(ans,(mp&l[2*(k-1)+1]).second.x);
}
break;
}
if(k==gnt){
flag=true;
break;
}
}
if(flag)
printf("Through all the pipe.\n");
else printf("%.2f\n",ans);
}
}