Copied from Eric Xiao
拔掉之後會使整張圖不連通的點
vis值就是DFS順序編號
low值:DFS樹中以某個節點為根的子樹
透過走最多一條back edge(tree edge不限)能走到的最小前序編號
int cnt = 0;
vector<int> G[MAXN];
int vis[MAXN], low[MAXN], iscut[MAXN];
void DFS(int u, int p) {
low[u] = vis[u] = ++cnt; // low至多是自己
int child = 0;
for(auto v : G[u]) {
if(!vis[v]) {
child++;
DFS(v, u);
low[u] = min(low[u], low[v]);
if(low[v] >= vis[u]) iscut[u] = 1; // 有子樹回不去
}
else if(vis[v] < vis[u] && v != p) {
low[u] = min(low[u], vis[v]); // back edge
}
}
if(p <= 0 && child == 1) iscut[u] = 0;
}
拔掉之後會使整張圖不連通的邊
一樣low值
int cnt = 0;
vector<int> G[MAXN], isbridge[MAXN];
int vis[MAXN], low[MAXN], iscut[MAXN];
void DFS(int u, int p) {
low[u] = vis[u] = ++cnt;
int child = 0;
for(int i = 0;i < G[u].size();i++) {
int v = G[u][i];
if(!vis[v]) {
child++;
DFS(v, u);
low[u] = min(low[u], low[v]);
if(low[v] > vis[u]) isbridge[u][i] = 1;
// 沒有等號 因為回的到v的話就切不斷(?)
}
else if(vis[v] < vis[u] && v != p) {
low[u] = min(low[u], vis[v]);
}
}
}
Broadcasting Corporation of China
就是沒有橋的一坨連通的東西QQ
很顯然先找到橋
然後拔掉
然後再對整張圖DFS一次
或是在DFS的時候不要把橋當邊(?)
Broadcasting Corporation of China
一張圖點雙連通的極大子圖
每條邊只屬於一個點雙連通分量
貌似要用stack維護某些東西
Code by Eric Xiao
有向圖的強連通分量
任何點都可以走到任何點的最大子圖
Step 1.
把原圖的所有邊倒過來
在新圖上DFS,記錄離開每個子點的時間。
Step 2.
在原圖上越晚離開的先DFS
每次DFS可以走到的節點即屬於同一個SCC。
#include<bits/stdc++.h>
#define int long long
using namespace std;
vector<int> adj[100000];
vector<int> rev[100000];
vector<int> SCC[100000];
int vis[1000000];
vector<int> W;
void dfs1(int n) {
vis[n] = 1;
for(auto i: rev[n]) {
if(!vis[i]) dfs1(i);
}
W.push_back(n);
}
int cnt;
void dfs2(int n) {
vis[n] = 1;
BCC[cnt].push_back(n);
for(auto i: adj[n]) {
if(!vis[i]) dfs2(i);
}
}
signed main() {
int n, m;
cin >> n >> m;
for(int i=0;i<m;i++) {
int a, b;
cin >> a >> b;
adj[a].push_back(b);
rev[b].push_back(a);
}
for(int i=0;i<n;i++) dfs1(i);
for(int i=0;i<n;i++) vis[i] = 0;
reverse(W.begin(), W.end());
for(auto i: W) {
dfs2(i), cnt++;
}
//
}
把一個雙連通分量視作一個點,把一個關節點也視作一個點
找關節點
給一張有向圖,請問最少要多少個起點才能遍歷每個點。
找橋連通分量