题意:
求出简单环的所有边,简单环即为边在一个环内
解析:
求出点双连通分量,如果一个连通分量的点数和边数相等,则为一个简单环
点双连通分量 任意两个点都至少存在两条点不重复的路径 即任意两条边都至少存在于一个简单环中
那么我们要求的那个简单环 是不是就是点双连通分量的特殊情况 即任意两条边只存在于一个简单环中‘
所以求点双连通分量 判断点数是否等于边数
#include <bits/stdc++.h> #define mem(a, b) memset(a, b, sizeof(a)) using namespace std; const int maxn = 1e6+10, INF = 0x7fffffff; int n, m; map<int, int> w[maxn]; int pre[maxn], iscut[maxn], bccno[maxn], dfs_clock, bcc_cnt, num[maxn]; vector<int> G[maxn], bcc[maxn]; vector<int> f; vector<int> g[maxn]; struct Edge{ int u, v; Edge(int u, int v): u(u), v(v){} }; stack<Edge> S; int dfs(int u, int fa) { int lowu = pre[u] = ++dfs_clock; int child = 0; for(int i=0; i<G[u].size(); i++) { int v = G[u][i]; Edge e = Edge(u, v); if(!pre[v]) { S.push(e); child++; int lowv = dfs(v, u); lowu = min(lowu, lowv); if(lowv >= pre[u]) { iscut[u] = true; bcc_cnt++; bcc[bcc_cnt].clear(); for(;;) { Edge x = S.top(); S.pop(); if(bccno[x.u] != bcc_cnt) { bcc[bcc_cnt].push_back(x.u); bccno[x.u] = bcc_cnt; } if(bccno[x.v] != bcc_cnt) { bcc[bcc_cnt].push_back(x.v); bccno[x.v] = bcc_cnt; } g[bcc_cnt].push_back(w[x.u][x.v]); if(x.u == u && x.v == v) break; } } } else if(pre[v] < pre[u] && v != fa) { S.push(e); lowu = min(lowu, pre[v]); } } if(fa < 0 && child == 1) iscut[u] = 0; return lowu; } void find_bcc() { mem(pre, 0); mem(iscut, 0); mem(bccno, 0); dfs_clock = bcc_cnt = 0; for(int i=1; i<=n; i++) if(!pre[i]) dfs(i, -1); } int main() { int u, v; cin >> n >> m; for(int i=1; i<=m; i++) { cin >> u >> v; w[u][v] = w[v][u] = i; G[u].push_back(v); G[v].push_back(u); } find_bcc(); for(int i=1; i<=bcc_cnt; i++) { if(g[i].size() == bcc[i].size()) for(int j=0; j<g[i].size(); j++) f.push_back(g[i][j]); } sort(f.begin(), f.end()); cout<< f.size() <<endl; for(int i=0; i<f.size(); i++) cout<< f[i] << " "; cout<< endl; return 0; }