tarjan割点:
对于一个无向图,判断无向图的那些点属于割点。
割点:
(上述图片素材来自B站董晓算法老师:【D16 Tarjan 割点】D16 Tarjan 割点_哔哩哔哩_bilibili)
核心代码
//无向图缩点 #include<bits/stdc++.h> using namespace std; const int N = 1e4 + 10; vector<int> e[N]; int dfn[N], low[N], tot; int root; bool cut[N]; //判断当前点是不是割点 void tarjan(int x) { dfn[x] = low[x] = tot++; int child = 0; //这里只用判断是否是符合条件的割点,故不需要用栈来存储和scc等来统计联通块 for(int y : e[x]) { if(!dfn[y]) { tarjan(y); low[x] = min(low[x], low[y]); if(low[y] >= dfn[x]) { child++; if(x != root || child > 1) { cut[x] = true; } } } else low[x] = min(low[x], dfn[y]); //现在是无向图,只要有连边,就可能在同一联通块 } }
板子题:
P3388 【模板】割点(割顶) - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)
//!!!警钟撅烂 按格式输出,其次不能在tarjan统计有多少个割点,应该将所有dfs进行完后for循环找一遍割点 #include<bits/stdc++.h> using namespace std; const int N = 2e4 + 10; vector<int> e[N]; int low[N], dfn[N], tot, root, num; bool cut[N]; void tarjan(int x) { dfn[x] = low[x] = ++tot; // cout << "low[x]" << x << "=" << low[x] << '\n'; int child = 0; for(int y : e[x]) { if(!dfn[y]) { tarjan(y); low[x] = min(low[x], low[y]); // cout << "low[" << x << ']' << '=' << low[x] << '\n'; if(low[y] >= dfn[x]) { child++; if(x != root || child > 1) { cut[x] = true; // cout << "cut:" << x << " child=" << child << '\n'; // num++; 不能再这里面进行统计,一个点可能多次被统计为割点 } } } else { low[x] = min(low[x], dfn[y]); // cout << "*low[" << x << "]=" << low[x] << '\n'; } } } int main() { int n, m; cin >> n >> m; for(int i = 1; i <= m; i++) { int a, b; cin >> a >> b; e[a].push_back(b); e[b].push_back(a); } for(int i = 1; i <= n; i++) { if(!dfn[i]) { root = i; tarjan(i); } } for(int i = 1; i <= n; i++) { if(cut[i]) num++; // 在这里统计!!! } cout << num << '\n'; for(int i = 1; i <= n; i++) { if(cut[i]) cout << i << ' '; } return 0; }