L2-001 紧急救援 (25 分) (最短路+路径打印)

链接:https://pintia.cn/problem-sets/994805046380707840/problems/994805073643683840

 


 

题目:

作为一个城市的应急救援队伍的负责人,你有一张特殊的全国地图。在地图上显示有多个分散的城市和一些连接城市的快速道路。每个城市的救援队数量和每一条连接两个城市的快速道路长度都标在地图上。当其他城市有紧急求助电话给你的时候,你的任务是带领你的救援队尽快赶往事发地,同时,一路上召集尽可能多的救援队。

输入格式:

输入第一行给出4个正整数N、M、S、D,其中N(2)是城市的个数,顺便假设城市的编号为0 ~ (;M是快速道路的条数;S是出发地的城市编号;D是目的地的城市编号。

第二行给出N个正整数,其中第i个数是第i个城市的救援队的数目,数字间以空格分隔。随后的M行中,每行给出一条快速道路的信息,分别是:城市1、城市2、快速道路的长度,中间用空格分开,数字均为整数且不超过500。输入保证救援可行且最优解唯一。

输出格式:

第一行输出最短路径的条数和能够召集的最多的救援队数量。第二行输出从S到D的路径中经过的城市编号。数字间以空格分隔,输出结尾不能有多余空格。

输入样例:

4 5 0 3
20 30 40 10
0 1 1
1 3 2
0 3 3
0 2 2
2 3 2

输出样例:

2 60
0 1 3

题意:
有n个城市 m条路径 起点为s 终点为d 每个城市拥有的价值为num[i] 求出一条最短路 使得路径最短并且尽可能价值最大
题目保证最佳选择存在并唯一
要求输出为最短路径条数和最大的价值和 路径打印

思路:
题目描述有一个坑点 即输出的最短路径条数不是指最后所求的最佳路径上有几条路 而是抛开价值的条件 单纯求距离最短的最短路径有几条
采用dijkstra的思路 用邻接矩阵来存图 但是有不足的地方 即邻接矩阵无法处理最短路计数中的重边 但是数据中应该没有重边数据 之后打算转用邻接表再写一遍
在寻边操作中 只要按照距离来找就可以 因为后来都会更新一遍
在松弛操作时 采用了两个关键词 主关键词为距离dis 记录当前总距离 副关键词为tot 记录当前总价值 如果是用距离来更新的 路径记录dis1[j]=dis1[tmp]
如果路径相等 不管是否用价值更新 路径记录均为dis1[j]+=dis1[tmp] 当前节点加上到tmp节点的最短路径数量
在路径输出部分 存储顺序为倒序 输出时要从后往前

代码:
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cmath>
#include <string>
#include <cstring>
#include <algorithm>

using namespace std;
typedef long long ll;
typedef unsigned long long ull;
const int inf=0x3f3f3f3f;
const int maxn=550;
int n,m,s,d,x,y,w;
int mp[maxn][maxn],dis[maxn],dis1[maxn],tot[maxn],vis[maxn],num[maxn],ans[maxn],path[maxn];

void dijkstra(int st){
    for(int i=0;i<n;i++){
        dis[i]=inf;
        vis[i]=0;
        dis1[i]=1;
    }
    dis[st]=0;tot[st]=num[st];
    vis[st]=0;dis1[st]=1;
    for(int i=0;i<n;i++){
        int tmp,minn=inf,maxx=-1;
        for(int j=0;j<n;j++){
            if(!vis[j] && (dis[j]<minn)){
                minn=dis[j];
                tmp=j;
            }
            
        }
        cout<<tmp<<" "<<minn<<" "<<dis1[tmp]<<endl;        
        if(minn==inf) break;vis[tmp]=1;
        for(int j=0;j<n;j++){
            if(!vis[j] && dis[tmp]+mp[tmp][j]<dis[j]){
                dis1[j]=dis1[tmp];
                dis[j]=dis[tmp]+mp[tmp][j];
                tot[j]=tot[tmp]+num[j];
                path[j]=tmp;
            }
            else if(!vis[j] && dis[tmp]+mp[tmp][j]==dis[j]){
                if(tot[tmp]+num[j]>tot[j]){
                    tot[j]=tot[tmp]+num[j];
                    path[j]=tmp;
                }
                dis1[j]+=dis1[tmp];//加上到tmp节点的最短路径数量
            }
        }
    }
}

int main(){
    scanf("%d%d%d%d",&n,&m,&s,&d);
    for(int i=0;i<n;i++){
        scanf("%d",&num[i]);
    }
    for(int i=0;i<n;i++)
        for(int j=0;j<n;j++)
                mp[i][j]=inf;
    for(int i=1;i<=m;i++){
        scanf("%d%d%d",&x,&y,&w);
        w=min(mp[x][y],w);
        mp[x][y]=mp[y][x]=w;
    }
    dijkstra(s);
    printf("%d %d\n",dis1[d],tot[d]);
    int cnt=0;    
    for(int i=d;i>=0;i=path[i]){
        ans[++cnt]=i;
        if(i==s) break;
    }
    for(int i=cnt;i>1;i--){
        printf("%d ",ans[i]);
    }
    printf("%d\n",ans[1]);
    return 0;
}
 
 

 

 

转载于:https://www.cnblogs.com/whdsunny/p/10609314.html

  • 0
    点赞
  • 0
    评论
  • 0
    收藏
  • 扫一扫,分享海报

参与评论 您还未登录,请先 登录 后发表或查看评论
©️2022 CSDN 皮肤主题:编程工作室 设计师:CSDN官方博客 返回首页
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值