某国王需要修路,王国有一个首都和多个城市,需要修路。已经有修路计划了,但是修路费用太高。
为了减少修路费用,国王决定从计划中去掉一些路,但是需要满足一下两点:
- 保证所有城市都能连通
- 所有城市到首都的最短路不变
思路:
在Dijkstra找最短路的时候,就记录一下费用
if(d[e.to] > d[v] + e.dist) { ... prev_min_cost[e.to] = e.cost; // 最短路必经之路,则费用也必须要 } else if(d[e.to] == d[v] + e.dist) // 最短路可选择之路,选择最小的费用连接 prev_min_cost[e.to] = min(prev_min_cost[e.to], e.cost);
程序
#include <iostream> #include <queue> #include <functional> #include <cstring> using namespace std; struct edge { int to, dist, cost; edge(int to, int dist, int cost) : to(to), dist(dist), cost(cost) {} bool operator<(const edge &b) const { return dist > b.dist; } }; vector<edge> G[10005]; int N, M; // 节点数,道路数 int d[10005]; // 距离源点s(s==1)的最小距离 int prev_min_cost[10005]; // 节点的邻接边最小花费 int ans; void dijkstra(int s) { memset(d, 0x3f, sizeof(d)); memset(prev_min_cost, 0x3f, sizeof(prev_min_cost)); d[s] = 0; priority_queue<edge> que; que.push(edge(s, d[s], 0)); while (!que.empty()) { edge p = que.top(); que.pop(); int v = p.to; if (d[v] < p.dist) continue; for (int i = 0; i<G[v].size(); ++i) { edge e = G[v][i]; if (d[e.to] > d[v] + e.dist) { d[e.to] = d[v] + e.dist; que.push(edge(e.to, d[e.to], G[v][i].cost)); prev_min_cost[e.to] = e.cost; // 最短路必经之路,则费用也必须要 } else if (d[e.to] == d[v] + e.dist) // 最短路可选择之路,选择最小的费用连接 prev_min_cost[e.to] = min(prev_min_cost[e.to], e.cost); } } } void solve() { dijkstra(1); for (int u = 2; u <= N; ++u) ans += prev_min_cost[u]; // 求出所有必须的费用(n-1条边) cout << ans << endl; } int main() { int u, v, d, c; while (cin >> N >> M) { for (int u = 1; u <= N; ++u) G[u].clear(); ans = 0; if (N == M && N == 0) break; for (int i = 0; i < M; ++i) { cin >> u >> v >> d >> c; G[u].push_back(edge(v, d, c)); // 构图 G[v].push_back(edge(u, d, c)); } solve(); } return 0; }