vector<int> g[maxn];
bool vis[maxn];
voiddfs(int u){
if (vis[u]) return;
vis[u] = true;
for (int v : g[u])
dfs(v);
}
算DFS序
vector<int> g[maxn];
int dfn[maxn];
int num = 0;
voiddfs(int u){
if (dfn[u]) return;
dfn[u] = ++num;
for (int v : g[u])
dfs(v);
}
树上DFS
vector<int> g[maxn];
voiddfs(int u, int p){
// 访问点ufor (int v : g[u])
if (v != p)
dfs(v, u);
}
观察
在 DFS 树里,节点的DFS序有何特点?
一般无向图上的DFS
设 是连通的无向图。考虑对 进行 DFS,可见
自环定为回边。
一组重边要么都定为回边,要么其中一条定为树边而其余定为回边。
DFS 与二分图检验
vector<int> g[maxn];
int color[maxn];
booldfs(int u, int c){
if (color[u])
return color[u] == c;
color[u] = c;
for (int v : g[u])
if (!dfs(v, -c))
returnfalse;
returntrue;
}
booltest_bipart(int n){
for (int i = 1; i <= n; i++)
if (!color[i] && !dfs(i, 1))
returnfalse;
returntrue;
}
vector<int> g[maxn];
int dfn[maxn], low[maxn];
int num = 0;
//在DFS树里p是u的父节点voiddfs(int u, int p){
low[u] = dfn[u] = ++num;
for (int v : g[u])
if (!dfn[v]) {
dfs(v, u);//uv是树边
low[u] = min(low[u], low[v]);
} elseif (v != p)//pu是树边
low[u] = min(low[u], dfn[v]);
}
用深度算 low 值
vector<int> g[maxn];
int depth[maxn];//点的深度int low[maxn];
int num = 0;
//在DFS树里p是u的父节点voiddfs(int u, int p){
low[u] = depth[u] = depth[p] + 1;
for (int v : g[u])
if (!dfn[v]) {
dfs(v, u);
low[u] = min(low[u], low[v]);
} elseif (v != p)
low[u] = min(low[u], depth[v]);
}
constint maxn = 2e4 + 5;
vector<int> g[maxn];
int dfn[maxn], low[maxn], num;
bool mark[maxn];
voiddfs(int u, int p){
dfn[u] = low[u] = ++num;
int nc = 0; //孩子数for (int v : g[u])
if (!dfn[v]) {
dfs(v, u);
nc++;
low[u] = min(low[u], low[v]);
//或 if (p && low[v] >= dfn[u])if (p && low[v] > dfn[p])
mark[u] = true;
} elseif (v != p)
low[u] = min(low[u], dfn[v]);
if (p == 0 && nc > 1)
mark[u] = true;
}
voidsolve(){
int n, m; cin >> n >> m;
for (int i = 0; i < m; i++) {
int u, v;
cin >> u >> v;
g[u].push_back(v);
g[v].push_back(u);
}
for (int i = 1; i <= n; i++)
if (!dfn[i])
dfs(i, 0);
int cnt = 0;
for (int i = 1; i <= n; i++)
cnt += mark[i];
cout << cnt << '\n';
for (int i = 1; i <= n; i++)
if (mark[i])
cout << i << ' ';
cout << '\n';
}
constint maxn = 1e5 + 5;
int dfn[maxn], low[maxn], num = 0;
int last[maxn];
vector<int> g[maxn];
vector<int> child[maxn];
voiddfs(int u, int p){ // p是u的父节点
low[u] = dfn[u] = ++num;
for (int v : g[u])
if (dfn[v] == 0) {// uv 是树边
child[u].push_back(v);
dfs(v, u);
low[u] = min(low[u], low[v]);
} elseif (v != p)// uv 是回边
low[u] = min(low[u], dfn[v]);
last[u] = num;
}
boolis_houdai(int a, int b){ //a是不是b的后代,a是否在子树b里return dfn[b] <= dfn[a] && dfn[a] <= last[b];
}
boolcmp(int a, int b){
return dfn[a] < dfn[b];
}
intwhich_child(int a, int b){ // 点a在点b的哪个孩子里if (dfn[a] <= dfn[b] || dfn[a] > last[b])
return0; //a不在b的子树里。auto it = upper_bound(child[b].begin(), child[b].end(), a, cmp);
return *(it - 1);
}
intmain(){
int n, m; cin >> n >> m;
for (int i = 0; i < m; i++) {
int u, v; cin >> u >> v;
g[u].push_back(v);
g[v].push_back(u);
}
dfs(1, 0); // 点1是DFS的起点int Q; cin >> Q;
while (Q--) {
int t, a, b, c, d;
cin >> t;
int cut = 0;
if (t == 1) {
cin >> a >> b >> c >> d;
//c和d是祖先——后代关系,令d是c的后代。if (dfn[c] > dfn[d]) swap(c, d);
cut = low[d] == dfn[d] && (is_houdai(a, d) ^ is_houdai(b, d));
} else {
cin >> a >> b >> c;
for (int x : {a, b}) {
int y = which_child(x, c);
if (y && low[y] >= dfn[c] && !is_houdai(a + b - x, y)) {
cut = 1;
break;
}
}
}
if (cut) cout << "no\n";
else cout << "yes\n";
}
return0;
}
constint maxn = 5e5 + 5;
int dfn[maxn], low[maxn], num;
vector<vector<int>> bcc;
stack<int> s;
voiddfs(int u, int p){
dfn[u] = low[u] = ++num;
s.push(u);
for (int v : g[u])
if (!dfn[v]) {
dfs(v, u);
low[u] = min(low[u], low[v]);
} elseif (v != p)
low[u] = min(low[u], dfn[v]);
if (p != -1 && low[u] >= dfn[p]) {
vector<int> cur;
while (1) {
int v = s.top(); s.pop();
cur.push_back(v);
if (v == u) break;
}
cur.push_back(p);
bcc.push_back(cur);
}
}
intmain(){
int n, m;
cin >> n >> m;
for (int i = 0; i < m; i++) {
int a, b;
cin >> a >> b;
g[a].push_back(b);
g[b].push_back(a);
}
for (int i = 0; i < n; i++)
if (g[i].empty())
bcc.push_back({i});
elseif (!dfn[i])
dfs(i, -1);
cout << bcc.size() << '\n';
for (auto b : bcc) {
cout << b.size();
for (int x : b)
cout << ' ' << x;
cout << '\n';
}
}
constint maxn = 2e5 + 5;
vector<int> g[maxn];
int dfn[maxn], num;
int low[maxn], parent[maxn];
voiddfs(int u, int p){
low[u] = dfn[u] = ++num;
parent[u] = p;
for (int v : g[u])
if (!dfn[v]) {
dfs(v, u);
low[u] = min(low[u], low[v]);
}
elseif (v != p)
low[u] = min(low[u], dfn[v]);
}
intmain(){
int n, m, a, b, c;
cin >> n >> m >> a >> b >> c;
for (int i = 0; i < m; i++) {
int u, v;
cin >> u >> v;
g[u].push_back(v);
g[v].push_back(u);
}
dfs(a, 0);
while (low[b] < dfn[parent[b]])
b = parent[b];
while (c)
if (c == b) {
cout << "Yes\n";
return0;
} else
c = parent[c];
cout << "No\n";
}
另一种写法
constint maxn = 2e5 + 5;
vector<int> g[maxn];
int dfn[maxn], last[maxn], num;
int low[maxn], parent[maxn];
voiddfs(int u, int p){
low[u] = dfn[u] = ++num;
parent[u] = p;
for (int v : g[u])
if (!dfn[v]) {
dfs(v, u);
low[u] = min(low[u], low[v]);
}
elseif (v != p)
low[u] = min(low[u], dfn[v]);
last[u] = num;
}
intmain(){
int n, m, a, b, c;
cin >> n >> m >> a >> b >> c;
for (int i = 0; i < m; i++) {
int u, v;
cin >> u >> v;
g[u].push_back(v);
g[v].push_back(u);
}
dfs(a, 0);
while (low[b] < dfn[parent[b]])
b = parent[b];
if (dfn[b] <= dfn[c] && dfn[c] <= last[b])
cout << "Yes\n";
else
cout << "No\n";
}
constint maxn = 2e5 + 5;
structEdge { int from, to; };
Edge e[maxn];
vector<int> g[maxn];
int dfn[maxn], low[maxn], num;
stack<int> s;
vector<vector<int>> bcce;
voiddfs(int u, int pe){ //pe是u的父边
low[u] = dfn[u] = ++num;
s.push(u);
for (int id : g[u]) {
int v = e[id].from ^ e[id].to ^ u;
if (!dfn[v]) {
dfs(v, id);
low[u] = min(low[u], low[v]);
}
elseif (id != pe)
low[u] = min(low[u], dfn[v]);
}
if (low[u] == dfn[u]) {
vector<int> cur;
while (1) {
int v = s.top(); s.pop();
cur.push_back(v);
if (v == u) break;
}
bcce.push_back(cur);
}
}
intmain(){
int n, m;
cin >> n >> m;
for (int i = 0; i < m; i++) {
int a, b;
cin >> a >> b;
e[i] = {a, b};
g[a].push_back(i);
g[b].push_back(i);
}
for (int i = 0; i < n; i++)
if (!dfn[i])
dfs(i, -1);
cout << bcce.size() << '\n';
for (auto b : bcce) {
cout << b.size();
for (int x : b)
cout << ' ' << x;
cout << '\n';
}
}