poj 1556 The Doors (线段之间位置的判断+最短路)

该博客主要介绍了POJ 1556题目,涉及在有限的室内墙壁障碍中寻找从(0, 5)到(10, 5)的最短路径问题。博主通过将每个墙壁视为三段障碍线,并考虑门的位置,转换为求解4*n+2个点间的最短路径问题。通过枚举路径并应用最短路算法,最终得出路径长度并输出结果。" 135496784,10186755,UML对象图解析与实战练习,"['UML图', '软件设计', '软考复习', '对象关系', '类图对比']

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

Description

You are to find the length of the shortest path through a chamber containing obstructing walls. The chamber will always have sides at x = 0, x = 10, y = 0, and y = 10. The initial and final points of the path are always (0, 5) and (10, 5). There will also be from 0 to 18 vertical walls inside the chamber, each with two doorways. The figure below illustrates such a chamber and also shows the path of minimal length.
这里写图片描述
Input

The input data for the illustrated chamber would appear as follows.

2
4 2 7 8 9
7 3 4.5 6 7

The first line contains the number of interior walls. Then there is a line for each such wall, containing five real numbers. The first number is the x coordinate of the wall (0 < x < 10), and the remaining four are the y coordinates of the ends of the doorways in that wall. The x coordinates of the walls are in increasing order, and within each line the y coordinates are in increasing order. The input file will contain at least one such set of data. The end of the data comes when the number of walls is -1.
Output

The output should contain one line of output for each chamber. The line should contain the minimal path length rounded to two decimal places past the decimal point, and always showing the two decimal places past the decimal point. The line should contain no blanks.
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

大致题意:放置了n个障碍墙,每个障碍墙上有两个门可以通过,告诉你每个障碍墙的门的坐标(即4个坐标),然后问你从点(0,5)到(10,5)的最短距离是多少。

思路:0<=n<=18,将每个障碍墙看成由三段障碍线构成,然后这些障碍线的端点加上起点和终点一共就4*n+2个点,假设起点为0,终点为4*n+1,我们将问题转化为求0号点到4*n+1号点的最短路。然后我们枚举两点做连线,如果与障碍线不冲突,那么该两点之间的距离即两个坐标点之间的距离,否则设为无穷大,然后用求最短路算法即可。

代码如下

#include<iostream>
#include<set>
#include<vector>
#include<algorithm>
#include<cstring>
#include<cstdio>
#include<cmath>
using namespace std;
typedef long long ll;
const double eps=1e-8;
const double INF=0x3f3f3f3f;

int dcmp(double x) 
{
    if(fabs(x)<eps) return 0;
    return x<0?-1: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.x + y*b.y;
    }
    double operator ^(const Point &b)const {
        return x*b.y - y*b.x;
    }
    int operator ==(const Point &b)const {
        if(dcmp(x-b.x)==0&&dcmp(y-b.y)==0)//如果两点相同返回0 
        return 0;
        else return 1;
    }
};
struct Line 
{
    Point a,b;
    Line() {}
    Line(Point _a,Point _b) 
    {
        a=_a;
        b=_b;
    }
};
const int N=100;
double dis[N][N];
Line line[N];
Point dian[N];

double dist(Point a,Point b) 
{
    return sqrt((b-a)*(b-a));//返回两个点之间的距离
}
double xmult(Point p0,Point p1,Point p2)//叉积 
{
    return (p1-p0)^(p2-p0);
}
bool inter(Line L1,Line L2)//判断两条线段是否相交,若相交返回1否则0 
{
    return
        max(L1.a.x,L1.b.x) >= min(L2.a.x,L2.b.x) &&
        max(L2.a.x,L2.b.x) >= min(L1.a.x,L1.b.x) &&
        max(L1.a.y,L1.b.y) >= min(L2.a.y,L2.b.y) &&
        max(L2.a.y,L2.b.y) >= min(L1.a.y,L1.b.y) &&
        dcmp((L2.a-L1.a)^(L1.b-L1.a))*dcmp((L2.b-L1.a)^(L1.b-L1.a)) <= 0 &&
        dcmp((L1.a-L2.a)^(L2.b-L2.a))*dcmp((L1.b-L2.a)^(L2.b-L2.a)) <= 0; 
}

int main() 
{
    int n;
    double x,y1,y2,y3,y4;
    while(1) 
    {
        scanf("%d",&n);
        if(n==-1)   break;
        for(int i=1;i<=n;i++)
        {
            scanf("%lf%lf%lf%lf%lf",&x,&y1,&y2,&y3,&y4);
            dian[4*i-3]=Point(x,y1);
            dian[4*i-2]=Point(x,y2);
            dian[4*i-1]=Point(x,y3);
            dian[4*i]=Point(x,y4);

            line[i*3-2]=Line(Point(x,0),Point(x,y1));
            line[i*3-1]=Line(Point(x,y2),Point(x,y3));
            line[i*3]=Line(Point(x,y4),Point(x,10)); 
        }
        dian[0]=Point(0,5);
        dian[4*n+1]=Point(10,5);

        for(int i=0;i<=4*n+1;i++)//枚举两个点连线 
        for(int j=i;j<=4*n+1;j++)
        {
            if(i==j||(dcmp(dian[i].x-dian[j].x)==0))//同一障碍墙上的点不考虑 
            {
                dis[i][j]=dis[j][i]=INF;
            }
            else 
            {
                Line L=Line(dian[i],dian[j]);
                int flag=1;
                for(int k=1;k<=3*n;k++)
                { 
                    if(L.a==line[k].a&&L.a==line[k].b&&L.b==line[k].a&&L.b==line[k].b)//注意要忽略掉所选的两个点本身所在的障碍线 
                    if(inter(L,line[k]))
                    {   
                        flag=0;
                        break;
                    }
                }
                if(flag)
                    dis[i][j]=dis[j][i]=dist(dian[i],dian[j]);
                else 
                    dis[i][j]=dis[j][i]=INF;
            }
        }

        for (int k = 0; k <= 4*n+1; k++)  //spfa求最短路
        for (int i = 0; i <= 4*n+1; i++)  
        for (int j = 0; j <= 4*n+1; j++)  
        {  
            if(dis[i][k]<INF&&dis[k][j]<INF)
            {
               dis[i][j]=min(dis[i][j],dis[i][k]+dis[k][j]);
            }
        }  

        printf("%.2f\n",dis[0][4*n+1]);
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值