POJ 1039--Pipe

20 篇文章 0 订阅

计算几何题目:题目给出一些弯管,问最后从入口发射的光线能到达的最右端。

参考《算法艺术与信息学竞赛》p359,最优的发射光线只能是某个拐点上端点和某个拐点下端点的连线。

根据以上原理,我们从左往右判断光线是否能通过拐点连接的纵墙,若能通过所有则输出Through all the pipe.

若首先交于某墙壁,求出交点,保存最大值输出。


#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
#define maxN 22

struct point
{
    float x,y;
};
point up[maxN];
point down[maxN];

float direction(point p1,point p2,point p3)         //差积
{
    return (p3.x-p1.x)*(p2.y-p1.y)-(p3.y-p1.y)*(p2.x-p1.x);
}

bool IsCrossBentWall(point upNode,point downNode,point wallUp, point wallDown)   //检查光线是否能跨越横坐标为墙壁
{
    float d1 = direction(upNode,downNode,wallUp);
    float d2 = direction(upNode,downNode,wallDown);
    if(d1*d2 <= 0)      //墙壁端点在光线两端或者端点在光线上
        return true;
    else
        return false;
}

float intersection(point p1,point p2,point p3,point p4)     //两条直线交点
{
    float k1 = (p2.y-p1.y)/(p2.x-p1.x);
    float k2 = (p4.y-p3.y)/(p4.x-p3.x);
    float dis =  (p3.y-k2*p3.x-p1.y+k1*p1.x)/(k1-k2);
    return dis;
}

float calcDis(int upNo,int downNo,int wallNo)
{
    float x1 = -1e6;
    float x2 = -1e6;
    if(IsCrossBentWall(up[upNo],down[downNo],up[wallNo-1],up[wallNo]))  //上壁
        x1 =  intersection(up[upNo],down[downNo],up[wallNo-1],up[wallNo]);
    if(IsCrossBentWall(up[upNo],down[downNo],down[wallNo-1],down[wallNo]))  //下壁
        x2 = intersection(up[upNo],down[downNo],down[wallNo-1],down[wallNo]);
    return x1>x2?x1:x2;             //选出与上下壁想交点的较大x
}

int main()
{
    int i,j,k;
    int N;
    char IsThroughAll;
    float maxDis,tmpDis;
    while(~scanf("%d",&N)&&N)
    {
        maxDis = -1e6;
        for(i = 0;i < N;i++)
        {
            scanf("%f%f",&up[i].x,&up[i].y);
            down[i].x = up[i].x;
            down[i].y = up[i].y-1;
        }
        for(i = 0;i < N;i++)
        {
            for(j = 0;j < N;j++)
            {
                IsThroughAll = false;
                if(i != j)
                {
                    for(k = 0;k < N;k++)
                    {
                        if(k != i&&k != j&&!IsCrossBentWall(up[i],down[j],up[k],down[k]))
                            break;
                    }
                    if(k == N)    //从前往后能通过最后一个纵墙
                    {
                        IsThroughAll = true;
                        break;
                    }
                    if(k > j)      //最后通过的墙壁在光线下端点的右边
                    {
                        tmpDis = calcDis(i,j,k);
                        if(maxDis < tmpDis)
                            maxDis = tmpDis;
                    }
                }
            }
            if(IsThroughAll)
                break;
        }
        if(IsThroughAll)
        {
            printf("Through all the pipe.\n");
            continue;
        }
        printf("%.2f\n",maxDis);
    }
    return 0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值