题目大意:
给一条曲折的管道,给出的形式是每一个转弯处口的坐标,求光线从入口进入能到的最远的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;
}