POJ 1556 The Doors(计算几何+Floyd)

本文介绍了一种利用最短路径算法解决特定场景下的路径寻找问题的方法。该场景包含多个障碍物(门),需要从起点到达终点,并且需要判断路径是否与障碍物相交。通过构建线段和点来模拟门的位置,并使用几何判断实现路径可行性验证。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Description
房间里有n堵墙,每面墙上有两扇门,求从房间最左端中点到最右端中点的最短路径
这里写图片描述
Input
多组用例,每组用例第一行为墙数n,之后n行每行五个浮点数x,y1,y2,y3,y4分别表示墙的横坐标,两扇门上下端点的纵坐标,以n=-1结束输入
Output
对于每组用例,输出从房间左端中点到右端中点的最短路径
Sample Input
1
5 4 6 7 8
2
4 2 7 8 9
7 3 4.5 6 7
-1
Sample Output
10.00
10.06
Solution
总共4*n+2个点,对于任意两点,判断它们是否与门相交,相交就连一条线,最后用最短路算法计算左端中点到右端中点的最短路径
Code

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
using namespace std;
const double eps = 1e-8;
#define maxn 111
#define INF 1<<29
int sgn(double x)
{
    if(fabs(x)<eps) return 0;
    if(x<0) return -1;
    else return 1;
}
struct Point
{
    double x,y;
    Point(){}
    Point(double _x,double _y)
    {
        x=_x;y=_y;
    }
    Point operator -(const Point &b)const
    {
        return Point(x-b.x,y-b.y);
    }
    double operator ^(const Point &b)const
    {
        return x*b.y-y*b.x;
    }
    double operator *(const Point &b)const
    {
        return x*b.x+y*b.y;
    }
};
struct Line
{
    Point s,e;
    Line(){}
    Line(Point _s,Point _e)
    {
        s=_s;e=_e;
    }
};
//判断线段相交
bool inter(Line l1,Line l2)
{
    return 
        max(l1.s.x,l1.e.x)>=min(l2.s.x,l2.e.x)&&
        max(l2.s.x,l2.e.x)>=min(l1.s.x,l1.e.x)&&
        max(l1.s.y,l1.e.y)>=min(l2.s.y,l2.e.y)&&
        max(l2.s.y,l2.e.y)>=min(l1.s.y,l1.e.y)&&
        sgn((l2.s-l1.s)^(l1.e-l1.s))*sgn((l2.e-l1.s)^(l1.e-l1.s))<=0&&
        sgn((l1.s-l2.s)^(l2.e-l2.s))*sgn((l1.e-l2.s)^(l2.e-l2.s))<=0;
}
double dist(Point a,Point b)
{
    return sqrt((b-a)*(b-a));
}
Line line[maxn];
double dis[maxn][maxn];
int main()
{
    int n;
    double x,y1,y2,y3,y4;
    while(scanf("%d",&n)&&n!=-1)
    {
        for(int i=1;i<=n;i++)
        {
            scanf("%lf%lf%lf%lf%lf",&x,&y1,&y2,&y3,&y4);
            line[2*i-1]=Line(Point(x,y1),Point(x,y2));//将门看作线段 
            line[2*i]=Line(Point(x,y3),Point(x,y4));
        }
        for(int i=0;i<=4*n+1;i++)//初始化 
            for(int j=0;j<=4*n+1;j++)
            {
                if(i==j)
                    dis[i][j]=0;
                else
                    dis[i][j]=INF;
            }
        for(int i=1;i<=4*n;i++)//判断中间4*n个点与左右端中点是否能连线 
        {
            int col=(i+3)/4;//该点所在墙的编号 
            bool flag=true;
            Point temp;
            if(i&1) temp=line[(i+1)/2].s;//判断该点是门的上端点还是下端点 
            else temp=line[(i+1)/2].e;
            for(int j=1;j<col;j++)//如果该点与它和左端中点间某堵墙的两个门都不相交则不能连线 
                if(inter(line[2*j-1],Line(Point(0,5),temp))==false&&inter(line[2*j],Line(Point(0,5),temp))==false)
                    flag=false;
            if(flag) dis[i][0]=dis[0][i]=dist(Point(0,5),temp);//可以连线 
            flag=true;
            for(int j=col+1;j<=n;j++)//如果该点与它和右端中点间某堵墙的两个门都不相交则不能连线
                if(inter(line[2*j-1],Line(Point(10,5),temp))==false&&inter(line[2*j],Line(Point(10,5),temp))==false)
                    flag=false;
            if(flag) dis[i][4*n+1]=dis[4*n+1][i]=dist(Point(10,5),temp);//可以连线 
        }
        for(int i=1;i<=4*n;i++)//判断中间4*n个点是否能相互连线 
            for(int j=i+1;j<=4*n;j++)
            {
                int col1=(i+3)/4;//第i个点所在墙的编号 
                int col2=(j+3)/4;//第j个点所在墙的编号 
                bool flag=true;
                Point t1,t2;
                if(i&1) t1=line[(i+1)/2].s;//判断该点是门的上端点还是下端点 
                else t1=line[(i+1)/2].e;
                if(j&1) t2=line[(j+1)/2].s;//判断该点是门的上端点还是下端点 
                else t2=line[(j+1)/2].e;
                for(int k=col1+1;k<col2;k++)//如果两点与其之间某堵墙的两个门都不相交则不能连线 
                    if(inter(line[2*k-1],Line(t1,t2))==false&&inter(line[2*k],Line(t1,t2))==false)
                        flag=false;
                if(flag) dis[i][j]=dis[j][i]=dist(t1,t2);//可以连线 
            }
        bool flag=true;
        //判断左右两端中点是否能直接连线 
        for(int i=1;i<=n;i++)//如果两中点与其之间的某堵墙的两个门都不相交则不能连线 
            if(inter(line[2*i-1],Line(Point(0,5),Point(10,5)))==false&&inter(line[2*i],Line(Point(0,5),Point(10,5)))==false)
                flag=false;
        if(flag) dis[0][4*n+1]=dis[4*n+1][0]=10;//可以连线 
        for(int k=0;k<=4*n+1;k++)//Floyd求最短路 
            for(int i=0;i<=4*n+1;i++)
                for(int j=0;j<=4*n+1;j++)
                    dis[i][j]=min(dis[i][j],dis[i][k]+dis[k][j]);
        printf("%.2lf\n",dis[0][4*n+1]);//输出左右两端中点的最短路径 
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值