# 題目: UVa 11631 - Dark Roads
# 題目說明
一個城市裡有很多的路相連,道路上每一公尺,路燈的 cost 為 1
找出每個路口能到任意其他路口,最多能減少多少 cost 的路燈
(整條路每一公尺有一個路燈)
INPUT:
每筆測資第一行有兩個整數 m
和 n
m
代表路口的數量n
代表道路的數量
接下來有 n
行,每行有三個整數 x
、 y
、 z
代表 x
與 y
路口間有一條長 z
的路
OUTPUT:
輸出最多能減少多少 cost 的路燈
# 解題方法
先將所有路口的編號及 cost 存入 edge
接著以 kruskcal
演算法,先對距離進行 sort
,再用 union_find
演算法判斷是否可連通
以總 cost,每次減掉最短路徑的 cost,即為答案
# 參考程式碼
#include <iostream> | |
#include <vector> | |
#include <tuple> | |
#include <algorithm> | |
using namespace std; | |
vector< tuple<int, int, int> > edge; | |
vector<int> parents; | |
vector<int> ranks; | |
int cost; | |
bool cmp(tuple<int, int, int> r1, tuple<int, int, int> r2) | |
{ | |
return get<2>(r1) < get<2>(r2); | |
} | |
bool union_find(int r1, int r2) | |
{ | |
// find root of r1 and r2 | |
while (r1 != parents[r1]) r1 = parents[r1]; | |
while (r2 != parents[r2]) r2 = parents[r2]; | |
// circle | |
if (r1 == r2) return false; | |
if (ranks[r1] > ranks[r2]) parents[r2] = r1; | |
else if (ranks[r2] > ranks[r1]) parents[r1] = r2; | |
else parents[r2] = r1, ++ranks[r1]; | |
return true; | |
} | |
int kruskcal(int m) | |
{ | |
sort(edge.begin(), edge.end(), cmp); | |
int side = 0; | |
for (auto& [r1, r2, w] : edge) | |
{ | |
if (side == m - 1) break; | |
// union find algorithm | |
if (union_find(r1, r2)) | |
{ | |
cost -= w; | |
++side; | |
} | |
} | |
return cost; | |
} | |
int main() | |
{ | |
// fast io | |
ios::sync_with_stdio(false); | |
cin.tie(nullptr); | |
cout.tie(nullptr); | |
int m, n; | |
while (cin >> m >> n, m && n) | |
{ | |
// init | |
edge.clear(); | |
parents.clear(); | |
ranks.assign(m, 0); | |
for (int i = 0; i < m; ++i) parents.emplace_back(i); | |
cost = 0; | |
// store roads in edges | |
while (n--) | |
{ | |
int x, y, z; | |
cin >> x >> y >> z; | |
cost += z; | |
edge.push_back({ x, y, z }); | |
} | |
// kruskcal algorithm | |
cout << kruskcal(m) << "\n"; | |
} | |
return 0; | |
} |
# 參考資料
https://www.larrysprognotes.com/UVa%20-%2011631/