POJ 1039 Pipe
题目大意:
给一条曲折的管道,给出的形式是每一个转弯处口的坐标,求光线从入口进入能到的最远的x点,如果能穿过管子则输出“Through all the pipe.”
首先要知道:
1、可以通过两向量的叉积来判断是否相交。具体见《算法艺术与信息学竞赛》P348开始向后很多页。
2、一条光线从入口到某一点必然会擦过一个上点(管转弯口上壁的点)和一个下点(管转弯口下壁的点)。
3、如果一条光线自始至终未擦到任何定点,这条光线是可以“优化的”。
4、“优化”就是可以通过旋转使它擦过一个上点和一个下点。
5、2、3、4点详见《算法艺术与信息学竞赛》P359.
解题思路:
1、先枚举光线是否能从入口射入,如果能判断能从第一个转弯处开始能穿过几个(判断能与多少个转弯处所在的竖直直线相交)。
2、如果遇到某一个转弯处穿不过了,计算入口到相交管壁的距离,有可能是上管壁,也有可能是下管壁,保存最大值。
3、如果能穿过所有的转弯处,就直接输出“Through all the pipe.”,否则输出最长距离。
下面是代码:
#include <stdio.h> #include <math.h> struct node { double x,y; } point[25]; double max(double a, double b) { return a > b ? a : b; } double xmult(node a,node b,node c) { return (a.x-c.x)*(b.y-c.y)-(b.x-c.x)*(a.y-c.y); } bool check(node a,node b,node c,node d) //管口判断 { double d1,d2; d1=xmult(a,b,c); d2=xmult(a,b,d); if(d1*d2<=0) return true; return false; } bool check2(node a,node b,node c,node d) //管壁判断 { double d1,d2; d1=xmult(a,b,c); d2=xmult(a,b,d); if(d1*d2>=0) return false; return true; } node does(node a) { a.y--; return a; }; node intersection(node a,node b ,node c, node d) //求两条直线的交点 { node temp=a; double t=((a.x-c.x)*(c.y-d.y)-(a.y-c.y)*(c.x-d.x))/((a.x-b.x)*(c.y-d.y)-(a.y-b.y)*(c.x-d.x)); temp.x+=(b.x-a.x)*t; temp.y+=(b.y-a.y)*t; return temp; } int main() { int n,i,j,k; while(scanf("%d",&n),n) { double d1,d2; node t; for(i=0; i<n; i++) { scanf("%lf%lf",&point[i].x,&point[i].y); } double x=point[0].x; for(i=0; i<n; i++) { for(j=0; j<n; j++) { if(check(point[i],does(point[j]),point[0],does(point[0]))) //检查既过上点i又过下点j的直线是否能过入口 { for(k=1; k<n; k++) { if(!check(point[i],does(point[j]),point[k],does(point[k])))//当这条直线不能通过第K个转弯口 { if(check2(point[i],does(point[j]),point[k],point[k-1])) //交点在上线段 { t=intersection(point[i],does(point[j]),point[k],point[k-1]); x=max(t.x,x); break; } if(check2(point[i],does(point[j]),does(point[k]),does(point[k-1]))) //交点在下线段 { t=intersection(point[i],does(point[j]),does(point[k]),does(point[k-1])); x=max(t.x,x); break; } x=max(x,point[k-1].x); //既不在上面也不再下面那么就是先一个入口的端点 ,就是上一次循环残留下来的情况,这里判断 break; } } if(k==n) { x=point[n-1].x+1; } } } } if(x>=point[n-1].x) { printf("Through all the pipe.\n"); } else { printf("%.2f\n",x); } } return 0; }