题意:
给定n个点m条边的无向图(保证连通)
问:至少加多少条边可以使图为双连通图)
思路:
双连通图即所有点都属于至少一个环中
显然我们先把图缩点得到一棵缩点树,问题就转成在缩点树上加最少多少条边使得图为双连通图。
对于n个节点的无根树,至少要 (1+left)/2 条边(left为叶子节点数)
#include<stdio.h> #include<string.h> #include<vector> #include<iostream> #include<queue> #include<stack> using namespace std; #define N 1005 #define M 1005 struct Edge{ int from, to, nex; bool cut; }edge[M*2]; int head[N], edgenum; void addedge(int u, int v){ Edge E={u,v,head[u],false}; edge[ edgenum ] = E; head[u] = edgenum++; } int n, m; int dfn[N], low[N], tarjan_time, tar, Stack[N*5], top; int Belong[N]; bool iscut[N]; void tarjan(int u, int fa){ dfn[u] = low[u] = ++tarjan_time; Stack[++top] = u; int child = 0, flag = 1; for(int i = head[u]; ~i; i = edge[i].nex) { int v = edge[i].to; if(flag && v==fa){flag = 0; continue;} if(!dfn[v]) { child++; tarjan(v, u); low[u] = min(low[u], low[v]); if(low[v] >= dfn[u]) { iscut[u] = true; if(low[v]>dfn[u]) edge[i].cut = edge[i^1].cut = true; } } else low[u] = min(low[u], dfn[v]); } if(child == 1 && fa<0)iscut[u] = false; if(low[u] == dfn[u]) { tar++; do { Belong[ Stack[top] ] = tar; }while(Stack[top--] != u); } } int du[N]; bool connect[N][N]; char tmp[1000]; void init(){ memset(head, -1, sizeof(head)), edgenum = 0; memset(dfn, 0, sizeof(dfn)); memset(low, 0, sizeof(low)); memset(iscut, 0, sizeof(iscut)); memset(Belong, -1, sizeof(Belong)); tarjan_time = 0; top = 0; tar = 0; memset(du, 0, sizeof(du)); for(int i = 0; i <= n; i++)memset(connect[i], 0, sizeof(connect[i])); } int main(){ int u, v; while(~scanf("%d %d", &n, &m)){ init(); while(m--){scanf("%d %d",&u,&v); addedge(u, v), addedge(v, u);} tarjan(1, -1); for(int i = 0; i < edgenum; i++)if(edge[i].cut) { int v = edge[i].to; du[Belong[v]]++; } int ans = 0; for(int i = 1; i <= tar; i++) ans += (du[i] == 1); printf("%d\n", (1+ans)>>1); } return 0; } /* 10 12 1 2 1 3 1 4 2 5 2 6 5 6 3 7 3 8 7 8 4 9 4 10 9 10 3 3 1 2 2 3 1 3 */