UVA_303_Pipe_(计算几何基础)
描述
一个管道,有n个拐点(包括起点),给出每个拐点的上面的坐标,下面的横坐标与上面相同,总坐标-1.一道光线从起点口射入,问最多射到x=?的位置碰壁.
303 - Pipe
Time limit: 3.000 seconds
Pipe |
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 , where . 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 there is a corresponding bottom point (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 and (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 on separate line. Each of the next n lines contains a pair of real values 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 , 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.如果某一道光没有擦过顶点,可以平移使解更优(碰到一个顶点).
2.如果某一道光只擦过一个顶点,可以旋转使解更优(碰到另一个顶点).
3.如果某一道光没有碰到上下各一个顶点,则可以绕前面或后面的点旋转,使解更优(碰到上下各一个顶点).
4.如果某一道光碰到了上下各一个顶点,则只有一个方向可以旋转,如果向该方向旋转可以使解更优,则旋转,直到再次碰到两个点.这两个点或者一上一下或者在同一方向,继续重复上述过程,直到第4步唯一能够旋转的方向不能使得解更优.
如此一来解法就明了了:因为最终的最优解一定是一上一下两个顶点的连线,所以枚举一上一下的点对,求每条直线的最优解即可.
注意:
1.无论是否时规范相交都要算交点,因为可能是撞在了拐点处,不规范相交的唯一交点求法相同(稍微推到一下就好了).
2.如果光线每通过i,在i-1的边找的时候即要找上面的也要找下面的,因为可能是擦过了上面,撞在了下面,或者擦过了下面,撞在了上面.
1 #include <bits/stdc++.h> 2 using namespace std; 3 4 const int maxn=20+5; 5 const double eps=1e-10; 6 int n; 7 double ans; 8 9 struct Point{ 10 double x,y; 11 Point(double x=0,double y=0):x(x),y(y){} 12 }up[maxn],down[maxn]; 13 typedef Point Vector; 14 Vector operator - (Vector a,Vector b){ return Vector(a.x-b.x,a.y-b.y); } 15 inline int dcmp(double x){ 16 if(fabs(x)<eps) return 0; 17 return x>0?1:-1; 18 } 19 inline double cross(Point a,Point b){ 20 return a.x*b.y-b.x*a.y; 21 } 22 inline bool segment_cross(Point a,Point b,Point c,Point d,Point &p){ 23 double s1,s2; 24 int d1,d2; 25 d1=dcmp(s1=cross(b-a,c-a)),d2=dcmp(s2=cross(b-a,d-a)); 26 if(d1*d2>0) return false; 27 else 28 p=Point((c.x*s2-d.x*s1)/(s2-s1),(c.y*s2-d.y*s1)/(s2-s1));//无论是否是规范相交,都要算交点 29 return true; 30 } 31 void ray(Point a,Point b){ 32 Point c; 33 if(!segment_cross(a,b,up[1],down[1],c)) return; 34 for(int i=2;i<=n;i++){ 35 if(!segment_cross(a,b,up[i],down[i],c)){//如果通过了拐口i,那么一定和up[i],down[i]所连直线相交 36 segment_cross(a,b,up[i-1],up[i],c);//如果没有通过,就在前一条的上面和下面找交点 37 ans=max(ans,c.x); 38 segment_cross(a,b,down[i-1],down[i],c); 39 ans=max(ans,c.x); 40 return; 41 } 42 } 43 ans=up[n].x; 44 } 45 void solve(){ 46 ans=up[1].x; 47 for(int i=1;i<=n;i++) 48 for(int j=1;j<=n;j++)//枚举每个一上一下的点对 49 if(i!=j) ray(up[i],down[j]); 50 if(ans==up[n].x) puts("Through all the pipe."); 51 else printf("%.2lf\n",ans); 52 } 53 int main(){ 54 while(scanf("%d",&n)&&n){ 55 for(int i=1;i<=n;i++){ 56 scanf("%lf%lf",&up[i].x,&up[i].y); 57 down[i].x=up[i].x; down[i].y=up[i].y-1; 58 } 59 solve(); 60 } 61 return 0; 62 }