【剑指紫金港】1003 Emergency Dijkstra算法&最短路数量

A 1003 Emergency

题目链接

Problem Description

As an emergency rescue team leader of a city, you are given a special map of your country. The map shows several scattered cities connected by some roads. Amount of rescue teams in each city and the length of each road between any pair of cities are marked on the map. When there is an emergency call to you from some other city, your job is to lead your men to the place as quickly as possible, and at the mean time, call up as many hands on the way as possible.

Input

Each input file contains one test case. For each test case, the first line contains 4 positive integers: N (≤500) - the number of cities (and the cities are numbered from 0 to N−1), M - the number of roads, C​1 and C​2 - the cities that you are currently in and that you must save, respectively. The next line contains N integers, where the i-th integer is the number of rescue teams in the i-th city. Then M lines follow, each describes a road with three integers c1 , c2 and L, which are the pair of cities connected by a road and the length of that road, respectively. It is guaranteed that there exists at least one path from C​1​​ to C​2​​ .

Output

For each test case, print in one line two numbers: the number of different shortest paths between C​1​​ and C2 , and the maximum amount of rescue teams you can possibly gather. All the numbers in a line must be separated by exactly one space, and there is no extra space allowed at the end of a line.

Sample Input:

5 6 0 2
1 2 1 5 3
0 1 1
0 2 2
0 3 1
1 2 1
2 4 1
3 4 1

Sample Output:

2 4

题目大意

给定一个无向图,n个点(编号为0到n-1),若干条边,每条边和每个点都有权值。求某个起点到某个终点的最短路数量,和所有最短路方案里,一条路线上所有点的权值和最大是多少。

解题思路

经典Dijsktra算法 + roads数组(存储最短路数量)+teams数组(存储最短路线上点的权值和最大值)。难点在于teams数组和roads数组的更新方式和判断条件。详情看代码和注释理解。

AC代码

#include <bits/stdc++.h>
using namespace std;
#define INF 0x3f3f3f3f
#define max(a, b) ((a) > (b) ? (a) : (b))

const int maxn = 504;

int graph[maxn][maxn];  //存图
int sos[maxn];  //每个城市等待救援的队伍数量
int vis[maxn];  //标记是否访问过
int d[maxn];  //起点到每个点的最短距离
int roads[maxn];  //起点到每个点的最短路数量
int teams[maxn];  //起点到每个点在距离最短的情况下最多救援几支队伍

int main(int argc, char **argv){
    int n,m,u,v,w,start,destination;
    scanf("%d%d%d%d",&n,&m,&start,&destination);
    for(int i=0;i<maxn;i++){
        for(int j=0;j<maxn;j++){
            graph[i][j]=INF;  //初始化,所有点都没有边相连
        }
    }
    fill(vis, vis+maxn, 0);  //初始化所有点都未访问
    fill(d, d+maxn, INF);  //初始化,起点到每一个点距离都为无穷大
    fill(roads, roads+maxn, 0);  //初始化,起点到每一个点的路线数都为0
    fill(teams, teams+maxn, 0);  //初始化,起点到每一个点能救援的队伍数量为0
    for(int i=0; i<n; i++){
        scanf("%d",&sos[i]);
    }
    for(int i=0; i<m; i++){
        scanf("%d%d%d",&u,&v,&w);
        graph[u][v]=w;
        graph[v][u]=w;
    }
    teams[start]=sos[start];  //起点的待救队伍是一定能救的
    roads[start]=1;  //起点到起点有且只有一条路
    d[start]=0;  //起点到起点的距离为0
    for(int i=0; i<n; i++){
        int p=-1; int minE = INF; //p用于记录,未访问的点集中到起点距离最短的点
        for(int j=0; j<n; j++){
            if(!vis[j] && d[j]<minE){
                p=j;
                minE=d[j];
            }
        }
        if(p==-1){break;}  //如果p是-1说明所有点都遍历完了,退出
        vis[p]=true;
        for(int j=0; j<n; j++){
            if(!vis[j] && graph[p][j]!=INF){
                if(d[j]>graph[p][j]+d[p]){
                    d[j]=graph[p][j]+d[p];
                    teams[j] = teams[p]+sos[j];  //更新最短路,可救援队伍数量为中转站p队伍数量与终点j队伍数量之和
                    roads[j] = roads[p];  //最短路径数就是起点到中转站p的最短路径数
                }else if(d[j] == graph[p][j]+d[p]){
                    teams[j] = max(teams[p]+sos[j],teams[j]);  //比较筛选出能救出队伍数的最大数量
                    roads[j] += roads[p];  //更新最短路数量
                }
            }
        }
    }
    printf("%d %d",roads[destination],teams[destination]);
    return 0;
}  
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

征服所有不服

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值