某国王需要修路,王国有一个首都和多个城市,需要修路。已经有修路计划了,但是修路费用太高。
为了减少修路费用,国王决定从计划中去掉一些路,但是需要满足一下两点:
- 保证所有城市都能连通
- 所有城市到首都的最短路不变
思路:
在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;
}