PAT甲级(Advanced Level) Practice 1003 Emergency

原题

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 Specification:

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, C1​ and C2​ - 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 C1​ to C2​.

Output Specification:

For each test case, print in one line two numbers: the number of different shortest paths between C1​ 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

题目翻译 

作为一个城市的紧急救援队队长,你得到了一张特殊的国家地图。地图上有几座分散的城市,由几条道路连接。地图上标明了每个城市的救援队数量以及任何一对城市之间每条道路的长度。当其他城市向您发出紧急求救信号时,您的任务是带领您的队员以最快的速度赶赴现场,同时在途中召集尽可能多的救援人员。

输入规范:
每个输入文件包含一个测试用例。每个测试用例的第一行包含 4 个正整数: N (≤ 500) - 城市数量(城市编号从 0 到 N-1),M - 道路数量,C1和C2 - 分别是您当前所在的城市和必须拯救的城市。下一行包含 N 个整数,其中第 i 个整数是第 i 个城市的救援队数量。接着是 M 行,每行描述一条道路,包含三个整数 C1, C2 和 L,它们分别是由一条道路连接的一对城市和该道路的长度。可以保证至少存在一条从 C1到 C2。

输出说明:
对于每个测试案例,请在一行中打印两个数字:C1 和 C2 之间不同最短路径的数量,以及您可能召集的最大救援队数量。一行中的所有数字必须用一个空格隔开,行尾不允许有多余的空格。

解题思路 

单源最短路, 使用dijkstra算法,本题M(道路数量)未知, 因此使用了两种dijkstra。注意输出为C1 和 C2 之间不同最短路径的数量而不是最短路距离!

代码1:朴素版dijkstra, 时间复杂度O(n^2)

#include <bits/stdc++.h>

using namespace std;

const int N = 1000;

int n, m, c1, c2;
int num[N];                                               // 每个城市救援队数量
int dist[N];
int res[N];                                               // 到达某一城市时救援队最大值
int sum[N];                                               // 到某一城市的最短路数量
bool st[N];                                               // 确定某一点的距离最小值是否已经确定
int g[N][N];                                              // 稠密图用邻接矩阵存储数据

void dijkstra(){
    memset(dist, 0x3f, sizeof dist);                      // 初始化所有点与C1的距离为正无穷
    dist[c1] = 0, res[c1] = num[c1], sum[c1] = 1;
    for(int i = 0; i < n; i ++) {
        int t = -1;                                       // t记录没有确定最短路径的节点中距离源点最近的点
        for(int j = 0; j < n; j ++)
            if(!st[j] && (t == -1 || dist[t] > dist[j]))
                t = j;
        st[t] = true; 
        
        for(int j = 0; j < n; j++) {                      // 遍历所有t能到达的点,更新最短距离
            if(dist[j] > dist[t] + g[t][j]) {
                dist[j] = dist[t] + g[t][j];
                res[j] = res[t] + num[j];
                sum[j] = sum[t];
            }
            else if(dist[j] == dist[t] + g[t][j]){        
                sum[j] += sum[t];
                res[j] = max(res[j], res[t] + num[j]);
            }
        }
    }
}

int main()
{
    scanf("%d%d%d%d", &n, &m, &c1, &c2);
    for(int i = 0; i < n; i ++) scanf("%d", &num[i]);
    memset(g, 0x3f, sizeof g);
    for(int i = 0; i < m; i ++) {
        int x, y, z;
        scanf("%d%d%d", &x, &y, &z);
        g[x][y] = min(g[x][y], z);
        g[y][x] = min(g[y][x], z);
    }

    dijkstra();
    
    printf("%d %d\n", sum[c2], res[c2]);

    return 0;
}

代码2:堆优化版dijkstra, 时间复杂度O(mlogn)

#include <bits/stdc++.h>
#include <queue> 

using namespace std;

typedef pair<int, int> PII;

const int N = 510, M = N * N;
int h[N], ne[M], e[M], w[M], idx;                            // 链表储存, w为边权
int st[N];
int dist[N];
int num[N];
int res[N], sum[N];          
int n, m, c1, c2;            

void add(int a, int b, int c){
    e[idx] = b, w[idx] = c, ne[idx] = h[a], h[a] = idx++;
}

void dijkstra(){
    memset(dist, 0x3f, sizeof dist);
    dist[c1] = 0, res[c1] = num[c1], sum[c1] = 1;

    priority_queue<PII, vector<PII>, greater<PII>> q;
    q.push({0, c1});

    while(q.size()){
        PII t = q.top();
        q.pop();
        int ver = t.second, distance = t.first;
        if(st[ver]) continue;          

        st[ver] = true;        
        
        for (int i = h[ver]; i != -1; i = ne[i]){    // 用t更新其他节点的距离 
            int j = e[i];
            if (dist[j] > distance + w[i]){
                sum[j] = sum[ver];                   // 最短路条数=上个点的条数
                res[j] = res[ver] + num[j];
                dist[j] = w[i] + distance;
                q.push({dist[j], j});                // 只有找到了最短路的点入队列 
            } 
            else if (dist[j] == distance + w[i]) {
                sum[j] += sum[ver];                  // 最短路条数+上个点的条数
                if (res[j] < res[ver] + num[j]) res[j] = res[ver] + num[j]; 
            }
        }
    }
}

int main(){
    memset(h, -1, sizeof h);
    cin >> n >> m >> c1 >> c2;
    for (int i = 0; i < n; i++) cin >> num[i];
    
    while (m --){
        int a, b, c;
        cin >> a >> b >> c;
        add(a, b, c);
        add(b, a, c);
    }
    
    dijkstra();
    
    cout << sum[c2] << " " << res[c2] << endl;
    
    return 0;
 } 

  • 24
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值