poj 1039 Pipe
管道问题:
题意:有一宽度为1的折线管道,上面各顶点为(x0,y0),(x1,y1)...(xn,yn),下面各顶点为(x0,y0-1),(x1,y1-1),....(xn,yn-1),假设管道不透明,不反射,光线从左边入口(x0,y0),(x0,y0-1)之间射入,向四面八方传播,问光线最远能射到的X的坐标或者射穿整个管道。
这题用的是枚举法,枚举所有的上下点,要是最优,一定是一个上点与一个下点,这样才能使X最大;
每次枚举一个上下点,就判断是否与线段相交,我用的方法是与它左边由对应的上下点作线段相交(即与(xm,ym),(xm,ym-1)的连线),如果他们的叉乘大于0,则没有相交;
反则,相交,枚举它左边的所有线段,如果没有一个相交的则代表光线可以通过,那么我们就继续往下枚举;
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#include<iostream> #include<cstdio> #include<cstring> #include<algorithm> #include<cmath> #include<string> #include<cstdlib> using namespace std; class Point { public: double x ,y; }up[24],down[24]; class Line { public: double x1,y1,x2,y2; }L_up[24],L_down[24],L[24]; double Max( double a , double b ) { return a > b ? a : b; } int Max( int a , int b ) { return a > b ? a : b; } int dcmp( double x ) { if( fabs( x ) < 1.0e-8 ) return 0; if( x < 0 ) return -1; else return 1; } void Get_line( int n ) { L[0].x1 = L[0].x2 = up[0].x; L[0].y1 = up[0].y ; L[0].y2 = down[0].y; for( int i = 1 ; i < n ; i++ ) { L[i].x1 = L[i].x2 = up[i].x; L[i].y1 = up[i].y ; L[i].y2 = down[i].y; L_up[i].x1 = up[i-1].x; L_up[i].x2 = up[i].x; L_up[i].y1 = up[i-1].y; L_up[i].y2 = up[i].y; L_down[i].x1=down[i-1].x;L_down[i].x2=down[i].x; L_down[i].y1=down[i-1].y;L_down[i].y2=down[i].y; } } double on_segment( Point p1 , Point p2 , double x , double y ) { return ( p1.x - x )*( p2.y - y ) - ( p2.x - x )*( p1.y - y ); } int segment( Point p1 , Point p2 , Line line ) { int d1 = dcmp(on_segment( p1 , p2 , line.x1 , line.y1 )); int d2 = dcmp(on_segment( p1 , p2 , line.x2 , line.y2 )); return d1*d2; } double Distance( double x1 , double y1 , double x2 , double y2 ) { return sqrt( ( x1 - x2 )*( x1 - x2 ) + ( y1 - y2 )*( y1 - y2 ) ); } double result( Point p1 , Point p2 , Line line ) { double x1,x2,y1,y2; double d1 = on_segment( p1 , p2 , line.x1 , line.y1 ); double d2 = on_segment( p1 , p2 , line.x2 , line.y2 ); y1 = ( d1 *line.x2 - d2 *line.x1 )/( d1 - d2); return y1; } void Solve( int n ) { double ans,max = -1*0x7fffffff; bool flag = 1; for( int i = 0; i < n && flag; i++ ) { for( int j=0; j < n && flag; j ++ ) { int t = Max( i , j ),k; for( k = 0 ; k < n && j!=i&& flag; k ++ ) { if( segment( up[i],down[j],L[k] ) > 0 ) break; } if( k == n ) flag = 0; else if( k >= t ) { if( segment( up[i],down[j],L_up[k] ) < 0 ) { max = Max(max , result( up[i],down[j],L_up[k] )); } else if( segment( up[i],down[j],L_down[k] ) < 0 ) { max = Max(max , result( up[i],down[j],L_down[k] )); } else if( segment( up[i],down[j],L_up[k] ) == 0 ) { max = Max(max , result( up[i],down[j],L_up[k] )); } else if( segment( up[i],down[j],L_down[k] ) == 0 ) max = Max(max , result( up[i],down[j],L_down[k] )); } } } if( flag ) printf( "%.2f\n",max ); else printf( "Through all the pipe.\n" ); } int main( ) { int n; while( scanf( "%d",&n ),n ) { for( int i = 0 ; 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; } Get_line( n ); Solve( n ); } return 0; }