L2-001 紧急救援-PAT团体程序设计天梯赛GPLT

题目来源:团体程序设计天梯赛-练习集
题目地址:L2-001 紧急救援

题目描述L2-001

题目大意

题目给出一张图,其中包括道路连接的城市和它们的距离,以及每个城市救援队的数量,最后求从出发地城市到目的地城市的最短路径条数、经过城市能召集到的最多救援队数量和最后选择的路径,可以结合样例理解题意:
1

题目分析

其实这道题目就是常规的最短路径题目,和模板有所不同的是,在求最短路径还要兼顾救援队的数量和统计最短路径条数。主要需要理解以下两种情况下的统计:

  • 当找更短的路径,即dis[v] > dis[u] + E[u][i].second时,
    因为经过城市 u u 去城市 v v 是更优方案,所以在先前肯定没有统计到这条路径上的救援队数量,所示直接用到城市 u u 后总的救援队数量加上城市 v v 的救援队数量。

    此时 u u v v 之间只有一条边相连,所以到 v v 的最短路径数也就等于到 u u 的最短路径数。 如下图所示,到城市 e e 的最短路径数,不会因为和城市 5 5 之间的一条路径增加,所以等于到城市 5 5 的最短路径数,即 t o t a l [ e ] = t o t a l [ 5 ] total[e] = total[5]

2

  • 当找到与最短路径相等的路径,即dis[v] == dis[u] + E[u][i].second时,
    需要判断能否在这个城市召集到更多的救援队,如果可以则更新救援队数量和经过的路径。

    由于是找到了长度一样的路径,相当多了一套到 v v 的方案,所以到城市 v v 总的最短路径数是要多加上到点 u u 的最短路径数( t o t a l [ u ] total[u] 。如下图所示,例如从 s s e e ,除了经过城市 5 5 以外,又发现了经过城市 6 6 且距离相同的路,那么结果应该要加上到城市 6 6 的最短路径数量( t o t a l [ 6 ] total[6] ), 所以最终 t o t a l [ e ] = t o t a l [ 5 ] + t o t a l [ 6 ] total[e] = total[5] + total[6]
    3

代码如下

#include <bits/stdc++.h>

using namespace std;
typedef pair<int, int> pii;
const int inf = 0x3f3f3f;
const int maxn =550;
int n, m, s, d;
/**
  * w[i]表示i城市拥有的救援队数量
  * sum[i]表示走到i城市可以召集到的救援队总数
  * total[i]表示走到i城市的路线数量
  */
int w[maxn], sum[maxn], total[maxn];
/**
  * dis[i]表示从源点到i点的最短距离
  * path[i]表示到i点的前驱节点
  */
int dis[maxn], vis[maxn], path[maxn];
vector<pii> E[maxn];

/**
  * 用dijstra算法求最短路径
  */
void dijstra(int s) {
    memset(vis, 0, sizeof(vis));
    //pair比较大小默认是先比较first,所以这里用first表示到源点的距离
    //改变优先队列的优先级,让到源点距离短的节点优先级高
    priority_queue<pii, vector<pii>, greater<pii> > q;
    // 初始化
    for (int i = 0; i < n; i++) dis[i] = inf;
    dis[s] = 0;
    sum[s] = w[s];
    total[s] = 1;
    q.push(pii(dis[s], s));
    while (!q.empty()) {
        int u = q.top().second;
        q.pop();
        if (vis[u]) continue;
        vis[u] = 1;
        for (int i = 0; i < E[u].size(); i++) {
            int v = E[u][i].first;
            if (dis[v] > dis[u] + E[u][i].second) {
                dis[v] = dis[u] + E[u][i].second;
                //直接加上该城市的救援队数量即可
                sum[v] = sum[u] + w[v];
                total[v] = total[u];
                path[v] = u;
                q.push(pii(dis[v], v));
            } else if (dis[v] == dis[u] + E[u][i].second) {
            	//如果在路径长度相等的情况下,该路径救援队数量更多
                if (sum[v] < sum[u] + w[v]) {
                	//更新救援队数量
                    sum[v] = sum[u] + w[v];
                    path[v] = u;
                }
                total[v] += total[u];
            }
        }
    }
}
/**
  * 用于输出经过的路径
  */
void output(int s, int d) {
    if (s == d) {
        printf("%d", s);
        return ;
    } else {
        output(path[s], d);
        printf(" %d", s);
    }
}

int main()
{
    scanf("%d %d %d %d", &n, &m, &s, &d);
    for (int i = 0; i < n; i++) scanf("%d", &w[i]);
    for (int i = 1; i <= m; i++) {
        int x, y, t;
        scanf("%d %d %d", &x, &y, &t);
        //由于是无向图,所以两个方向的边都要加上
        E[x].push_back(pair<int, int>(y, t));
        E[y].push_back(pair<int, int>(x, t));
    }
    dijstra(s);
    printf("%d %d\n", total[d], sum[d]);
    output(d, s);
    return 0;
}


如果本文对你有所帮助,别忘了点赞哦~

发布了63 篇原创文章 · 获赞 120 · 访问量 2万+

猜你喜欢

转载自blog.csdn.net/weixin_42292229/article/details/104257040