PAT 甲级 1003

PAT 1003

题目介绍:

给出城市的连接状况和每个城市的救援队伍的数量。给定起点和终点,求出起点到终点最短路径的个数,以及找出一条可以包含救援队最多的最短路径,输出最多可以累计的救援队的数目。

题目思路:

本题目很明显是一个Dijkstra的最短路算法,但是题目的真正考察点在于求解最短路的个数和在多条最短路径上求解出累计救援队伍数目最多的个数。路的条数和救援队伍的数目都采用累计求和的思想。Dijkstra算法的核心是把结点划分成两个集合:已经求得最短路径的和未求得最短路径的。这个关系用一个用一个不等式来维护,具体参考算法导论有关章节。在这里的最短路算法,利用到了堆优化,每次从最小堆中取出两个集合间的最短距离进行不等关系的维护。
如果可以缩短当前u->v的路径,那么,dist[v]=dist[u]+w(u,v)num[v]=team[v]+num[v]表示v的救援队伍的总数是v自己的加上u之前累加的;road[v]=road[u]是因为u->v只有一条路,那么从原点到v还是等于从原点到u的数目。
如果遇到了dist[v]=dist[u]+w(u,v)的情况,说明还有还有从原点到v不经过u的路径的长度等于从原点到v经过u的路径的长度;那么,此时的road[v]肯定要加上road[u]的,才是更新后的路径的数目,即road[v]+=road[u]。注意,如果队伍数目的更新条件num[it->v] <= num[t] + team[it->v],也就是说,如果有更多的队伍数目,才进行更新!

AC代码:

#include <bits/stdc++.h>
using namespace std;
const int MAXN = 503; // 最大的结点个数
const int INF = 10000000;
int N, M, BEGIN, END; // 结点个数,边个数,起点,终点
// team是每个城市的队伍个数,num是最短路上城市累计的个数,dist是最短路径,road是路径累加的个数
int team[MAXN], num[MAXN], dist[MAXN], road[MAXN];
bool flag[MAXN];       // 加入最短路的标记
struct Node {
    int v, w;
};
vector<Node>G[MAXN];  // 建图

struct cmp {          // 自定义比较结构
    bool operator()(const int& a, const int& b) {
        return dist[a] > dist[b];
    }
};

void Create() {
    int u, v, w;
    for(int i = 0; i < M; ++i) {
        cin >> u >> v >> w;
        Node tmp;
        tmp.v = v;
        tmp.w = w;
        G[u].push_back(tmp);   // 注意是无向图!!!!!
        tmp.v = u;
        tmp.w = w;
        G[v].push_back(tmp);
    }
}

void Dijkstra(int u) {
    for(int i = 0; i < N; ++i) {
        dist[i] = INF;
        num[i] = team[i];
        flag[i] = false;
        road[i] = 0;
    }
    dist[u] = 0;
    road[u] = 1;
    priority_queue<int, vector<int>, cmp>Q;
    Q.push(u);
    while(!Q.empty()) {
        int t = Q.top();
        Q.pop();
        if(flag[t]) {
            continue;
        }
        flag[t] = true;
        for(auto it = G[t].begin(); it != G[t].end(); it++) {
            if(flag[it->v]) {
                continue;
            } else if(dist[it->v] > dist[t] + it->w) {
                dist[it->v] = dist[t] + it->w;
                num[it->v] = team[it->v] + num[t];
                road[it->v] = road[t];
                Q.push(it->v);
            } else if(dist[it->v] == dist[t] + it->w ) {
                if(num[it->v] <= num[t] + team[it->v]) {
                    num[it->v] = num[t] + team[it->v];
                }
                road[it->v] += road[t];    // 路径加1
            }
        }
    }
}

int main() {
    cin >> N >> M >> BEGIN >> END;
    for(int i = 0; i < N; ++i) {
        cin >> team[i];
    }
    Create();
    Dijkstra(BEGIN);
    cout << road[END] << " " << num[END];
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值