FZU2209 老S的旅行计划(最短路,dijkstra)

本文介绍了一种基于最短路径算法的动态规划方法,用于解决带有时间变量的旅行路线问题。该方法通过三维数组记录不同时间点之间的成本,并利用Dijkstra算法进行路径规划。

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

Problem Description

老S在某城市生活的非常不自在,想趁着ICPC举办期间在省内转转。已知老S所在的省有N个城市,M条无向边(对于某一对结点可能出现重边)。由于省内的交通相当糟糕,通过某条边所需要花费的时间受到一天中不同时刻的影响。此外对于某一时刻(一天24小时的任意一个整点算一个时刻),从任何方向通过无向边所需要的时间相同。现在老S想请你帮他规划一下旅行路线。

Input

第一行输入为一个整数T表示测试个数T

对于每一个测试的第一行为3个整数N,M,K,其中K表示老S的询问数

之后有2M行,一组2行共M组。每组第一行是两个整数x,y表示第x个城市与第y个城市之间有一条无向边。

每组第二行有24个整数costi表示在第i个时刻通过这条无向边需要消耗的时间(单位为小时)。并且保证cost[i]<=coust[i+1]+1(0<=i<=22)且cost[23]<=cost[0]+1。

之后有K每行有两个整数D和S表示询问,从1号城市的第S个时刻出发,最终目的地为城市D所需要最少几个小时,此外如果老S不能到达目标城市则输出-1。

Limit:

1 <=x, y<=N.

1 <=all Cost values<=50.

1 <=D<=N.

0 <=S<=23.

1 <=T<=100.

2 <=N<= 20.

1 <=M<=100.

1 <=K<= 100.

Output

对于任意一个样例输出仅有一行包括”Case #x: “其中x表示第x个样例,之后有K个整数用空格分隔开,分别表示老S的K个询问的答案。

Sample Input

3
3 3 2
1 2
1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
1 3
3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 
2 3
1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
2 1
3 3
3 1 2
1 2
1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
2 2
3 4
3 3 3
1 2
7 23 23 25 26 26 25 24 23 22 21 20 19 18 17 16 15 14 13 12 11 10 9 8
1 3
10 11 15 26 30 29 28 27 26 25 24 23 22 21 20 19 18 17 16 15 14 13 12 11
2 3
7 29 28 27 26 26 25 24 23 22 21 20 19 18 17 16 15 14 13 12 11 10 9 8
2 14
3 3
3 21

Sample Output

Case #1: 1 2
Case #2: 1 -1
Case #3: 17 26 13

思路

本题就是在最短路的基础上变形了一下,在这个题中,两点之间的距离(花费时间)是变化的,我们可以使用三维数组cost[u][v][j]来记录从u点到v点在第j个时间的花费。

因为时间是24小时制,所以要对时间进行处理,每一次循环以后当前的时刻是(s+dis[kk])%24

最后只需要判断dis[d]的值是不是inf,储存结果输出答案

代码

#include <stdio.h>
#include <algorithm>
#include <iostream>
#include <string.h>
#include <string>
using namespace std;
#define mem(a,b) memset(a,b,sizeof(a))
#define inf 0x3f3f3f3f
const int N=100+10;
int cost[N][N][30],u,v,ans[N];
int dis[N],vis[N];
int t,n,m,k,d,s;
void dijkstra()
{
    for(int i=1; i<=n; i++)
    {
        vis[i]=0;
        dis[i]=inf;
    }
    dis[1]=0;
    for(int i=1; i<=n; i++)
    {
        int kk=0,minn=inf;
        for(int j=1; j<=n; j++)
            if(!vis[j]&&dis[j]<=minn)
            {
                minn=dis[j];
                kk=j;
            }
        vis[kk]=1;
        for(int j=1; j<=n; j++)
            if(!vis[j]&&dis[kk]+cost[kk][j][(s+dis[kk])%24]<dis[j])
                dis[j]=dis[kk]+cost[kk][j][(s+dis[kk])%24];
    }
}
int main()
{
    int q=1;
    scanf("%d",&t);
    while(t--)
    {
        mem(cost,inf);
        scanf("%d%d%d",&n,&m,&k);
        for(int i=1; i<=m; i++)
        {
            scanf("%d%d",&u,&v);
            for(int j=0; j<=23; j++)
            {
                int x;
                scanf("%d",&x);
                if(x<cost[u][v][j])
                    cost[v][u][j]=cost[u][v][j]=x;
            }
        }
        for(int i=1; i<=k; i++)
        {
            scanf("%d%d",&d,&s);
            dijkstra();
            if(dis[d]==inf)
                ans[i]=-1;
            else
                ans[i]=dis[d];
        }
        printf("Case #%d:",q++);
        for(int i=1; i<=k; i++)
            printf(" %d",ans[i]);
        puts("");
    }
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值