Skip to Content

Planets and Kingdoms

Complejidad temporal: O(N+M)\mathcal O(N+M)

Basta ejecutar el algoritmo de SCC de Kosaraju  o Tarjan  sobre el grafo.

Luego asignamos a cada componente un IDID (empezando desde 11).

Con el SCC de Kosaraju:

#include <bits/stdc++.h> using namespace std; /** * Descripción: Algoritmo de Kosaraju, DFS dos veces para generar * componentes fuertemente conexas en orden topológico. $a,b$ * están en la misma componente si existen $a\to b$ y $b\to a$. * Tiempo: O(N+M) * Fuente: Wikipedia * Verificación: POI 8 peaceful commission */ struct SCC { int N; vector<vector<int>> adj, radj; vector<int> todo, comp, comps; vector<bool> vis; void init(int _N) { N = _N; adj.resize(N), radj.resize(N), comp = vector<int>(N, -1), vis.resize(N); } void ae(int x, int y) { adj[x].push_back(y), radj[y].push_back(x); } void dfs(int x) { vis[x] = 1; for (int y : adj[x]) if (!vis[y]) dfs(y); todo.push_back(x); } void dfs2(int x, int v) { comp[x] = v; for (int y : radj[x]) if (comp[y] == -1) dfs2(y, v); } void gen() { // llena allComp for (int i = 0; i < N; i++) if (!vis[i]) dfs(i); reverse(begin(todo), end(todo)); for (int x : todo) if (comp[x] == -1) { dfs2(x, x), comps.push_back(x); } } }; int main() { int n, m, a, b; cin >> n >> m; SCC graph; graph.init(n); while (m--) { cin >> a >> b; graph.ae(--a, --b); } graph.gen(); int ID[200000]{}; int ids = 0; for (int i = 0; i < n; i++) { if (!ID[graph.comp[i]]) { ID[graph.comp[i]] = ++ids; } } cout << ids << '\n'; for (int i = 0; i < n; i++) { cout << ID[graph.comp[i]] << " \n"[i == n - 1]; } }

Con el SCC de Tarjan

#include <bits/stdc++.h> using namespace std; /** * Descripción: Tarjan, DFS una sola vez para generar * componentes fuertemente conexas en orden topológico. $a,b$ * están en la misma componente si existen $a\to b$ y $b\to a$. * Usa menos memoria que Kosaraju porque no guarda las aristas inversas. * Tiempo: O(N+M) * Fuente: KACTL * https://github.com/kth-competitive-programming/kactl/blob/master/content/graph/SCC.h * Verificación: https://cses.fi/problemset/task/1686/ */ struct SCC { int N, ti = 0; vector<vector<int>> adj; vector<int> disc, comp, st, comps; void init(int _N) { N = _N; adj.resize(N), disc.resize(N), comp = vector<int>(N, -1); } void ae(int x, int y) { adj[x].push_back(y); } int dfs(int x) { int low = disc[x] = ++ti; st.push_back(x); // disc[y] != 0 -> en la pila for (int y : adj[x]) if (comp[y] == -1) low = min(low, disc[y] ?: dfs(y)); if (low == disc[x]) { // nueva SCC, desapilar hasta encontrar x comps.push_back(x); for (int y = -1; y != x;) comp[y = st.back()] = x, st.pop_back(); } return low; } void gen() { for (int i = 0; i < N; i++) if (!disc[i]) dfs(i); reverse(begin(comps), end(comps)); } }; int main() { int n, m, a, b; cin >> n >> m; SCC graph; graph.init(n); while (m--) { cin >> a >> b; graph.ae(--a, --b); } graph.gen(); int ID[200000]{}; int ids = 0; for (int i = 0; i < n; i++) { if (!ID[graph.comp[i]]) { ID[graph.comp[i]] = ++ids; } } cout << ids << '\n'; for (int i = 0; i < n; i++) { cout << ID[graph.comp[i]] << " \n"[i == n - 1]; } }