算法笔记/USACO Guide GOLD金组Graphs并查集Disjoint Set Union
是什么
并查集 (DSU) 数据结构能够向图添加边并测试图的两个顶点是否相连。它将两个集合合并,再询问两个元素是否在一个集合当中。
以下是 DSU 的实现。它利用从小到大合并和路径压缩快速执行并集查找。由于真实实践非常简单,他可以用来代替用于计算连接组件的 DFS。
#include <bits/stdc++.h>
using namespace std;
class DisjointSets {
private:
vector<int> parents;
vector<int> sizes;
public:
DisjointSets(int size) : parents(size), sizes(size, 1) {
for (int i = 0; i < size; i++) { parents[i] = i; }
}
/** @return the "representative" node in x's component */
int find(int x) { return parents[x] == x ? x : (parents[x] = find(parents[x])); }
/** @return whether the merge changed connectivity */
bool unite(int x, int y) {
int x_root = find(x);
int y_root = find(y);
if (x_root == y_root) { return false; }
if (sizes[x_root] < sizes[y_root]) { swap(x_root, y_root); }
sizes[x_root] += sizes[y_root];
parents[y_root] = x_root;
return true;
}
/** @return whether x and y are in the same connected component */
bool connected(int x, int y) { return find(x) == find(y); }
};
Topological Sort 拓扑排序
有向图由只能沿一个方向遍历的边组成。此外,非循环图定义了一种不包含环的图,因此,它无法遍历一条或多条边并返回到开始的节点。将这些定义放在一起,有向无环图(有时缩写为 DAG)是一种具有只能在一个方向上遍历的边并且不包含环的图。
一个拓扑排序的一个有向无环图是其顶点的线性排序,使得对于每个有向边u到v从顶点u到顶点 v,序列中u会出现在v之前。
#include <algorithm>
#include <iostream>
#include <vector>
using std::cout;
using std::endl;
using std::vector;
vector<int> top_sort;
vector<vector<int>> graph;
vector<bool> visited;
void dfs(int node) {
for (int next : graph[node]) {
if (!visited[next]) {
visited[next] = true;
dfs(next);
}
}
top_sort.push_back(node);
}
int main() {
int n, m; // The number of nodes and edges respectively
std::cin >> n >> m;
graph = vector<vector<int>>(n);
for (int i = 0; i < m; i++) {
int a, b;
std::cin >> a >> b;
graph[a - 1].push_back(b - 1);
}
visited = vector<bool>(n);
for (int i = 0; i < n; i++) {
if (!visited[i]) {
visited[i] = true;
dfs(i);
}
}
std::reverse(top_sort.begin(), top_sort.end());
vector<int> ind(n);
for (int i = 0; i < n; i++) { ind[top_sort[i]] = i; }
// Check if the topological sort is valid
bool valid = true;
for (int i = 0; i < n; i++) {
for (int j : graph[i]) {
if (ind[j] <= ind[i]) {
valid = false;
goto answer;
}
}
}
answer:;
if (valid) {
for (int i = 0; i < n - 1; i++) { cout << top_sort[i] + 1 << ' '; }
cout << top_sort.back() + 1 << endl;
} else {
cout << "IMPOSSIBLE" << endl;
}
}