Graph Theory II
Review
Shortest Paths
Spanning Tree
複習
1. 術語
2. 定義
Review
Terminology
術語
Review
Definitions
定義
Review
Unweighted Shortest Path
vector<vector<int>> adj(n + 1);
while (m--) {
int u, v;
cin >> u >> v;
adj[u].push_back(v);
}
vector<vector<int>> adj(n + 1);
while (m--) {
int a, b;
cin >> a >> b;
adj[a].push_back(b);
adj[b].push_back(a);
}
Review
複習一下
寫過的可以試一下
最短路
1. Bellman-Ford
2. Dijkstra
3. Floyd-Warshall
Shortest Paths
Shortest Path
Weighted
Shortest Paths
Bellman-Ford
Shortest Paths
Implement
for (int i = 1; i <= n; i++) distance[i] = INF;
distance[x] = 0;
for (int i = 1; i <= n - 1; i++) {
for (auto e : edges) {
int a, b, w;
tie(a, b, w) = e;
distance[b] = min(distance[b], distance[a] + w);
}
}
Shortest Paths
Dijkstra
Shortest Paths
Proof
Shortest Paths
Implement
for (int i = 1; i <= n; i++) dist[i] = INF;
dist[start] = 0; // 起點距離為 0
pq.push({0, start}); // 預設是由大到小
while (!pq.empty()) {
long long c = pq.top().front;
int u = pq.top().second;
pq.pop();
if (-c != dist[u]) continue; // 如果該節點已處理過
for (auto [v, w] : adj[u]) {
if (dist[u] + w < dist[v]) {
dist[v] = dist[u] + w;
pq.push({-dist[v], v}) // 將 dist 變成負數
// 由小到大排序
}
}
}
Shortest Paths
Floyd-Warshall
Shortest Paths
Implement
for (int i = 1; i <= n; i++) {
for (int j = 1; j <= n; j++) {
if (i == j) distance[i][j] = 0;
else if (adj[i][j]) distance[i][j] = adj[i][j];
else distance[i][j] = INF;
}
}
for (int k = 1; k <= n; k++) { // 中繼點,記得放在最外圈
for (int i = 1; i <= n; i++) {
for (int j = 1; j <= n; j++) {
distance[i][j] = min(distance[i][j],
distance[i][k]+distance[k][j]);
}
}
}
Shortest Paths
負環
Shortest Paths
Summary
題單
Shortest Paths
生成樹
1. DSU
2. Kruskal's
3. Prim's
Spanning Tree
Minimum Spanning Tree
最小生成樹
Spanning Tree
題目
Spanning Tree
Kruskal's algorithm
Spanning Tree
Proof
Spanning Tree
Implement
併查集(Disjoint Set Union)
Shortest Paths
Implement
for (int i = 1; i <= n; i++) link[i] = i; // 各自為代表
for (int i = 1; i <= n; i++) size[i] = 1; // 紀錄代表 i 所在集合的大小
int find(int x) {
while (x != link[x]) x = link[x];
return x;
}
void unite(int a, int b) {
a = find(a);
b = find(b);
// 這是啟發式合併,可以避免惡意測資
if (size[a] < size[b]) swap(a, b);
size[a] += size[b];
link[b] = a;
}
Spanning Tree
Prim's algorithm
Shortest Paths
AC Code
#include <iostream>
#include <vector>
#include <algorithm>
#include <utility>
using namespace std;
// 這邊的 DSU 是用路徑壓縮,有興趣可以去查一下
struct DSU {
vector<int> boss;
DSU(int n) : boss(n + 1) {
for (int i = 1; i <= n; i++) {
boss[i] = i;
}
}
int query(int a) {
if (boss[a] == a) return a;
return boss[a] = query(boss[a]);
}
bool unite(int a, int b) {
a = query(a), b = query(b);
if (a == b) return false;
boss[a] = query(b);
return true;
}
};
int main() {
int n, m;
cin >> n >> m;
vector<pair<int, pair<int, int>>> adj;
for (int i = 0; i < m; i++) {
int a, b, c;
cin >> a >> b >> c;
adj.push_back({c, {a, b}});
}
sort(adj.begin(), adj.end());
DSU dsu(n);
long long ans = 0;
int node = 0;
for (int i = 0; i < m; i++) {
int a, b, c;
a = adj[i].second.first;
b = adj[i].second.second;
c = adj[i].first;
if (dsu.unite(a, b)) {
ans += c;
node++;
}
}
if (node != n - 1) cout << "IMPOSSIBLE\n";
else cout << ans << '\n';
}