POJ3177 Redundant Paths
双连通图:无向图中每两个顶点都存在完全不同的两条路径
给定一个无向图,问要给它增加多少条边可以把它变成双连通图。
用tarjan缩点,可以得到一棵树,添加(叶子结点+1)/2条边可以使其成环,也就是答案~
为了避开重边,这题用邻接矩阵存,wa了一晚上QAQ~
#include<cstdio> #include<algorithm> #include<vector> #include<stack> using namespace std; const int maxn=5014; int g[maxn][maxn]; int N,M,x,y; int low[maxn]; int dfn[maxn]; stack<int> st; int cnt; int scc; int pos[maxn]; int in[maxn]; void tarjan (int x,int pre) { low[x]=dfn[x]=++cnt; st.push(x); for (int i=1;i<=N;i++) { if (i==pre) continue; if (!g[x][i]) continue; if (!low[i]) { tarjan(i,x); low[x]=min(low[x],low[i]); } else if (!pos[i]) low[x]=min(low[x],dfn[i]); } if (low[x]==dfn[x]) { scc++; while (1) { int u=st.top(); st.pop(); low[u]=low[x]; pos[u]=scc; if (u==x) break; } } } void build () { for (int i=1;i<=N;i++) { for (int j=1;j<=N;j++) { if (pos[i]!=pos[j]&&g[i][j]) in[pos[j]]++; } } } int main () { scanf ("%d %d",&N,&M); for (int i=0;i<M;i++) { scanf ("%d %d",&x,&y); g[x][y]=g[y][x]=1; } for (int i=1;i<=N;i++) if (!low[i]) tarjan(i,i); build (); int leaves=0; for (int i=1;i<=scc;i++) { if (in[i]==1) leaves++; } printf ("%d\n",(leaves+1)/2); return 0; }