GYM 101147 B.Street(Floyd)

本文介绍了一种计算在包含多个遮阳棚的矩形区域内,从底部到顶部暴露在太阳下的最短路径长度的算法。通过将问题转化为图论中的最短路径问题,并利用Floyd算法进行求解。

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

Description
一个l*u的区域,里面有一些遮阳棚,现在要从下底边跑到上底边,起点终点位置任意,只要起点在下底边终点在上底边即可,问暴露在太阳下的最短距离是多少
Input
第一行一整数T表示用例组数,每组用例首先输入三整数n,l,u分别表示遮阳棚数量,区域的长和宽,之后n行每行输入四个整数h,w,d,k,h和w表示该遮阳棚的长和宽,d表示该遮阳棚下底边和该区域下底边的距离,k表示该遮阳棚和该区域的左边或者左边相邻(0表示和左边相邻,1表示和右边相邻)(1<=n<=100,1<=l,u,h,w,d,k<=1e9,保证遮阳棚均在该区域内,且任意两个遮阳棚不会有重叠区域)
Output
输出从下底边跑到上底边暴露在太阳下的最短距离
Sample Input
2
1 200 100
10 50 50 0
4 200 100
20 10 10 1
80 20 20 0
20 90 120 0
30 8 150 1
Sample Output
190.000000
70.198039
Solution
把下底边看作起点s,上底边看作终点e,s到任一遮阳棚的距离是该遮阳棚的d值,任一遮阳棚到e的距离是l-h-d,任意两个遮阳棚之间的最短距离需要讨论几种情况,我是求出一个点到一个矩形的最短距离,然后对于两个遮阳棚之间的最短距离,只需要求出其中一个遮阳棚的四个顶点到另一个遮阳棚的最短距离取最小值即可,知道这n+2个点之间的距离后跑一遍Floyd即可
Code

#include<cstdio>
#include<iostream>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<vector>
#include<queue>
#include<map>
#include<set>
#include<ctime>
using namespace std;
typedef long long ll;
#define INF 0x3f3f3f3f
#define maxn 111
int T,n,l,u;
struct node
{
    int x1,y1,x2,y2;
    node(){};
    node(int _x1,int _y1,int _x2,int _y2)
    {
        x1=_x1,y1=_y1,x2=_x2,y2=_y2;
    }
}p[maxn];
double dis[maxn][maxn];
double get_dis(double x1,double y1,double x2,double y2)
{
    double x=x2-x1,y=y2-y1;
    return sqrt(x*x+y*y);
}
double get(double x,double y,int i)
{
    int x1=p[i].x1,y1=p[i].y1,x2=p[i].x2,y2=p[i].y2;
    if(x>=x2)
    {
        if(y>=y2)return get_dis(x,y,x2,y2);
        if(y<=y1)return get_dis(x,y,x2,y1);
        return x-x2;
    }
    if(x<=x1)
    {
        if(y>=y2)return get_dis(x,y,x1,y2);
        if(y<=y1)return get_dis(x,y,x1,y1);
        return x1-x;
    }
    if(y>=y2)return y-y2;
    return y1-y;
}
int main()
{
    freopen("street.in","r",stdin);
    scanf("%d",&T);
    while(T--)
    {
        scanf("%d%d%d",&n,&l,&u);
        for(int i=1;i<=n;i++)
        {
            int h,w,d,k;
            scanf("%d%d%d%d",&h,&w,&d,&k);
            if(k)p[i]=node(u-w,d,u,h+d);
            else p[i]=node(0,d,w,h+d);
        }
        for(int i=0;i<=n+1;i++)
            for(int j=0;j<=n+1;j++)
                dis[i][j]=1e12;
        for(int i=1;i<=n;i++)dis[0][i]=p[i].y1,dis[i][n+1]=l-p[i].y2;
        for(int i=1;i<=n;i++)
            for(int j=1;j<=n;j++)
            {
                int x1=p[i].x1,y1=p[i].y1,x2=p[i].x2,y2=p[i].y2;
                double temp=get(x1,y1,j);
                temp=min(temp,get(x1,y2,j));
                temp=min(temp,get(x2,y1,j));
                temp=min(temp,get(x2,y2,j));
                dis[i][j]=temp;
            }
        for(int i=1;i<=n;i++)
            for(int j=1;j<=n;j++)
                dis[i][j]=min(dis[i][j],dis[j][i]);
        for(int k=0;k<=n+1;k++)
            for(int i=0;i<=n+1;i++)
                for(int j=0;j<=n+1;j++)
                    dis[i][j]=min(dis[i][j],dis[i][k]+dis[k][j]);
        printf("%.6f\n",dis[0][n+1]);
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值