http://poj.org/problem?id=1039
The GX Light Pipeline Company started to prepare bent pipes for the new transgalactic light pipeline. During the design phase of the new pipe shape the company ran into the problem of determining how far the light can reach inside each component of the pipe. Note that the material which the pipe is made from is not transparent and not light reflecting.
Each pipe component consists of many straight pipes connected tightly together. For the programming purposes, the company developed the description of each component as a sequence of points [x1; y1], [x2; y2], . . ., [xn; yn], where x1 < x2 < . . . xn . These are the upper points of the pipe contour. The bottom points of the pipe contour consist of points with y-coordinate decreased by 1. To each upper point [xi; yi] there is a corresponding bottom point [xi; (yi)-1] (see picture above). The company wants to find, for each pipe component, the point with maximal x-coordinate that the light will reach. The light is emitted by a segment source with endpoints [x1; (y1)-1] and [x1; y1] (endpoints are emitting light too). Assume that the light is not bent at the pipe bent points and the bent points do not stop the light beam.
Input
The input file contains several blocks each describing one pipe component. Each block starts with the number of bent points 2 <= n <= 20 on separate line. Each of the next n lines contains a pair of real values xi, yi separated by space. The last block is denoted with n = 0.
Output
The output file contains lines corresponding to blocks in input file. To each block in the input file there is one line in the output file. Each such line contains either a real value, written with precision of two decimal places, or the message Through all the pipe… The real value is the desired maximal x-coordinate of the point where the light can reach from the source for corresponding pipe component. If this value equals to xn, then the message Through all the pipe. will appear in the output file.
Sample Input
4
0 1
2 2
4 1
6 4
6
0 1
2 -0.6
5 -4.45
7 -5.57
12 -10.8
17 -16.55
0
Sample Output
4.67
Through all the pipe.
题目大意:给出一个管道,它的宽度是
1
1
1,起始的坐标是
(
x
1
,
y
1
)
(x_{1},y_{1})
(x1,y1),这个管道有许多转折的地方,给出上层转折的地方的坐标
(
x
i
,
y
i
)
(x_{i},y_{i})
(xi,yi),那么下层转折的坐标就是
(
x
i
,
y
i
−
1
)
(x_{i},y_{i}-1)
(xi,yi−1),管道结束的坐标是
(
x
n
,
y
n
)
(x_{n},y_{n})
(xn,yn),现在有无数条光线从管道入口射入,光线不会反射不会折射,问最远能达到的横坐标是多少。若能穿过管道则输出
T
h
r
o
u
g
h
a
l
l
t
h
e
p
i
p
e
.
Through all the pipe.
Throughallthepipe.
思路:能够到达最远点的直线必然通过管道的一个上管道壁的折点和一个下管道壁的折点,因此我们可以枚举折点,并把同一横坐标的上下折点连成线段,看我们枚举的折点构成的线段与线段是否相交,若与
n
n
n条线段都相交,那么光一定可以穿过整个管道。否则若直线与第
k
k
k条线段不想交了,那么直线要么射在第
k
−
1
k-1
k−1块上管道上,要么射在第
k
−
1
k-1
k−1块下管道上,分别计算两种情况下的交点取横坐标最大值即可。
#include<iostream>
#include<cstdio>
#include<cmath>
#include<vector>
#include<algorithm>
#include<cstring>
using namespace std;
const double pi=acos(-1.0);//弧度pi
const double eps=1e-10;//精度
struct point
{
double x,y;
point(double a=0,double b=0)
{
x=a,y=b;
}
friend point operator * (point a,double b)
{
return point(a.x*b,a.y*b);
}
friend point operator * (double a,point b)
{
return point(b.x*a,b.y*a);
}
point operator - (const point &b)const
{
return point(x-b.x,y-b.y);
}
point operator + (const point &b)const
{
return point(x+b.x,y+b.y);
}
point operator / (const double b)const
{
return point(x/b,y/b);
}
bool operator < (const point &b)const//按坐标排序
{
if(fabs(x-b.x)<eps)
return y<b.y-eps;
return x<b.x-eps;
}
void transxy(double sinb,double cosb)//逆时针旋转b弧度
{ //若顺时针 在传入的sinb前加个-即可
double tx=x,ty=y;
x=tx*cosb-ty*sinb;
y=tx*sinb+ty*cosb;
}
void transxy(double b)//逆时针旋转b弧度
{ //若顺时针传入-b即可
double tx=x,ty=y;
x=tx*cos(b)-ty*sin(b);
y=tx*sin(b)+ty*cos(b);
}
double norm()
{
return sqrt(x*x+y*y);
}
};
inline double dot(point a,point b)//点积
{
return a.x*b.x+a.y*b.y;
}
inline double cross(point a,point b)//叉积
{
return a.x*b.y-a.y*b.x;
}
inline double dist(point a,point b)//两点间距离
{
return (a-b).norm();
}
inline int sgn(double x)
{
if(fabs(x)<eps)
return 0;
if(x>0)
return 1;
return -1;
}
typedef point Vector;
struct line
{
point s,e;
line(){}
line(point _s,point _e)
{
s=_s,e=_e;
}
};
double xmult(point p1,point p2,point p3)//p1p2 X p1p3
{
return cross(p2-p1,p3-p1);
}
bool seg_inter_line(line l1,line l2)//判断直线l1 与 线段l2 是否相交
{
return sgn(xmult(l2.s,l1.s,l1.e))*sgn(xmult(l2.e,l1.s,l1.e))<=0;
}
inline double dis_point_seg(point p,line l)//计算点到线段距离
{
if(sgn(dot(p-l.s,l.e-l.s))<0)//不存在 返回点到线段端点的距离
return (p-l.s).norm();
if(sgn(dot(p-l.e,l.s-l.e))<0)//不存在 返回点到线段端点的距离
return (p-l.e).norm();
return fabs(cross(l.s-p,l.e-p))/dist(l.s,l.e);//|叉积|=2*S△
}
void popint_proj_line(point p,point s,point t,point &cp)//计算点p到线段st的垂足 保存在cp中
{
double r=dot(t-s,p-s)/dot(t-s,t-s);
cp=s+r*(t-s);
}
bool point_on_seg(point p,point s,point t)//判断点p 是否在线段st上 包括端点
{
return sgn(cross(p-s,t-s))==0&&sgn(dot(p-s,p-t))<=0;
}
bool parallel(line a,line b)//判断a b 是否平行
{
return !sgn(cross(a.s-a.e,b.s-b.e));
}
bool line_make_point(line a,line b,point &res)//判断直线a b是否相交 若相交则返回true并把交点存在res中
{
if(parallel(a,b))
return 0;
double s1=cross(a.s-b.s,b.e-b.s);
double s2=cross(a.e-b.s,b.e-b.s);
res=(s1*a.e-s2*a.s)/(s1-s2);
return 1;
}
line move_d(line a,double len)//将直线a沿法向量方法平移len
{
point d=a.e-a.s;
d=d/d.norm();
d.transxy(pi/2);
return line(a.s+d*len,a.e+d*len);
}
int n;
point up[25];
point down[25];
int main()
{
while(~scanf("%d",&n)&&n)
{
double ans=-1e16;
for(int i=1;i<=n;i++)
{
scanf("%lf%lf",&up[i].x,&up[i].y);
down[i].x=up[i].x,down[i].y=up[i].y-1;
}
bool flag=1;
int k;
for(int i=1;i<=n&&flag;i++)
{
for(int j=1;j<=n&&flag;j++)
{
if(j==i)
continue;
for(k=1;k<=n;k++)
if(!seg_inter_line(line(up[i],down[j]),line(up[k],down[k])))//没有交点
break;
if(k>n)
flag=0;
else if(k>max(i,j))
{
point tmp;
if(line_make_point(line(up[i],down[j]),line(up[k-1],up[k]),tmp))
ans=max(ans,tmp.x);
if(line_make_point(line(up[i],down[j]),line(down[k-1],down[k]),tmp))
ans=max(ans,tmp.x);
}
}
}
if(!flag)
printf("Through all the pipe.\n");
else
printf("%.2f\n",ans);
}
return 0;
}