和上一题一样 给你一张图 求最少加几条边可以使全图双连通 多了重边
多加了一个bool的数组 判断重边 重边只算一条
还是用了有向图的强连通分量 与有向图相比 多了 1.参数fa 父节点 2.如果子节点是其父节点 continue
#include <cstdio> #include <cstring> #include <vector> #include <stack> #include <algorithm> using namespace std; const int maxn = 5010; vector <int> G[maxn]; bool ok[maxn][maxn]; int pre[maxn]; int low[maxn]; int sccno[maxn]; int dfs_clock; int scc_cnt; stack <int> S; int n, m; int degree[maxn]; int Topo[maxn][maxn]; void dfs(int u, int fa) { pre[u] = low[u] = ++dfs_clock; S.push(u); for(int i = 0; i < G[u].size(); i++) { int v = G[u][i]; if(v == fa) continue; if(!pre[v]) { dfs(v, u); low[u] = min(low[u], low[v]); } else low[u] = min(low[u], pre[v]); } if(low[u] == pre[u]) { scc_cnt++; while(1) { int x = S.top(); S.pop(); sccno[x] = scc_cnt; if(x == u) break; } } } void find_scc() { dfs_clock = scc_cnt = 0; memset(sccno, 0, sizeof(sccno)); memset(pre, 0, sizeof(pre)); for(int i = 1; i <= n; i++) if(!pre[i]) dfs(i, -1); } int main() { while(scanf("%d %d", &n, &m) != EOF) { for(int i = 1; i <= n; i++) G[i].clear(); memset(ok, false, sizeof(ok)); while(m--) { int u, v; scanf("%d %d", &u, &v); if(!ok[u][v]) { G[u].push_back(v); G[v].push_back(u); ok[u][v] = true; } } find_scc(); memset(degree, 0, sizeof(degree)); for(int i = 1; i <= n; i++) { for(int j = 0; j < G[i].size(); j++) { int v = G[i][j]; if(sccno[i] != sccno[v]) { degree[sccno[i]]++; degree[sccno[v]]++; } } } int ans = 0; for(int i = 1; i <= scc_cnt; i++) if(degree[i] == 2) ans++; printf("%d\n", (ans + 1) / 2); } return 0; }