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;
}


posted @ 2014-01-03 21:45  、小呆  阅读(142)  评论(0编辑  收藏  举报