poj1039:题目链接
题目大意:一条管子有n个折点,给出管子上壁n个点的坐标(x1,y1)(x2,y2)....,x1<x2<x3.....,其中管子粗是1,也就是说横截面的上面坐标(x,y),下面坐标(x,y-1)。问一束光从开始的点打入,最远照射到的位置,输出位置,或是全程
如果想让光照的最远,那么除了全程的可能外,光一定会与某一个管壁相交,并且会与管中的两个节点相交,否则就可以调整光的角度,使其照的更远,枚举这两个点的位置,然后逐个点处判断相交的位置。
#include <cstdio>
#include <cstring>
#include <cmath>
#include <algorithm>
using namespace std ;
#define eqs 1e-9
/*
两直线相交,求焦点
ax + by + c = 0 ;
ux + vy + w = 0 ;
a/u != b/v 防止平行
交点:( (b*w-v*c)/(a*v-u*b) , (c*u-a*w)/(a*v-u*b) )
*/
struct point
{
double x , y ;
} p[30];
int n ;
double a[4][4] = { {0,0,0,0},{0,-1,0,0},{0,0,0,-1},{0,-1,0,-1} } ;
double solve(point u,point v) {
double a = (u.y-v.y)/(u.x-v.x) , b = u.y-a*u.x ;
double x , y , ans = 0.0 ;
int flag = 0 , i ;
y = a*p[0].x + b ;
if( y-p[0].y >= eqs || p[0].y-1.0-y >= eqs ) return ans ;
for(i = 1 ; i < n ; i++) {
y = a*p[i].x + b ;
if( y-p[i].y > eqs ) {
flag = 1 ;
break ;
}
else if( p[i].y-1.0-y > eqs ) {
flag = 2 ;
break ;
}
else
ans += (p[i].x-p[i-1].x) ;
}
if( !flag ) return ans ;
u = p[i-1] , v = p[i] ;
if( flag == 2 ) u.y -= 1.0 , v.y -= 1.0 ;
double k = (u.y-v.y)/(u.x-v.x) , c = u.y-k*u.x ;
x = (b-c)/(k-a) ;
ans += (x-p[i-1].x) ;
return ans ;
}
int main()
{
int i , j , k ;
double max1 , temp ;
point u , v ;
while( scanf("%d", &n) && n )
{
max1 = 0.0 ;
for(i = 0 ; i < n ; i++)
scanf("%lf %lf", &p[i].x, &p[i].y) ;
for(i = 0 ; i < n ; i++)
for(j = i+1 ; j < n ; j++)
for(k = 0 ; k < 4 ; k++) {
u.x = p[i].x + a[k][0] ; u.y = p[i].y + a[k][1] ;
v.x = p[j].x + a[k][2] ; v.y = p[j].y + a[k][3] ;
temp = solve(u,v) ;
if( temp > max1 )
max1 = temp ;
}
if( fabs(p[n-1].x-p[0].x-max1) < eqs )
printf("Through all the pipe.\n") ;
else
printf("%.2lf\n", p[0].x+max1) ;
}
return 0 ;
}