http://poj.org/problem?id=3177
One visualization of the paths is:
1 2 3 +---+---+ | | | | 6 +---+---+ 4 / 5 / / 7 +Building new paths from 1 to 6 and from 4 to 7 satisfies the conditions.
1 2 3 +---+---+ : | | : | | 6 +---+---+ 4 / 5 : / : / : 7 + - - - -Check some of the routes:
看ζёСяêτ - 小優YoU 的解析很明白的哦,讲述的太明白了
少在缩点树上增加多少条树边,使得这棵树变为一个双连通图”。
首先知道一条等式:
若要使得任意一棵树,在增加若干条边后,变成一个双连通图,那么
至少增加的边数 =( 这棵树总度数为1的结点数 + 1 )/ 2
http://blog.csdn.net/lyy289065406/article/details/6762370
#include <iostream> #include <cstring> #include <cstdio> #include <algorithm> #include <cmath> #include <cstdlib> #include <limits> #include <queue> #include <stack> #include <vector> #include <map> using namespace std; #define N 5005 #define INF 0xfffffff #define PI acos (-1.0) #define EPS 1e-8 vector <vector <int> > G; int n, m, Time, ans, cnt, top; int low[N], dfn[N], ft[N], f[N], eg[N], Stack[N]; void Init (); void tarjan (int u, int fa); void solve (); int main () { while (~scanf ("%d%d", &n, &m)) { int a, b; Init (); while (m--) { scanf ("%d%d", &a, &b); G[a].push_back (b); G[b].push_back (a); } solve (); } return 0; } void Init () { G.clear (); G.resize (n+1); memset (low, 0, sizeof (low)); memset (dfn, 0, sizeof (dfn)); memset (Stack, 0, sizeof (Stack)); memset (f, 0, sizeof (f)); memset (ft, 0, sizeof (ft)); Time = top = ans = cnt = 0; } void tarjan (int u, int fa) { low[u] = dfn[u] = ++Time; Stack[top++] = u; f[u] = fa; int len = G[u].size (), v, k = 0; for (int i=0; i<len; i++) { v = G[u][i]; if (v == fa && !k)//如果有重边的话,第一条边可以不用走 { k++; continue; } if (!dfn[v]) { tarjan (v, u); low[u] = min (low[u], low[v]); } else low[u] = min (low[u], dfn[v]); } if (low[u] == dfn[u]) { do { v = Stack[--top]; ft[v] = cnt; }while (u != v); cnt++; } } void solve () { int deg[N] = {0}; for (int i=1; i<=n; i++) if (!low[i]) tarjan (i, i); for (int i=1; i<=n; i++) { int v = f[i]; if (ft[i] != ft[v]) deg[ft[i]]++, deg[ft[v]]++;//计算叶子节点的度 } for (int i=0; i<cnt; i++) if (deg[i] == 1) ans++;//度为1 printf ("%d\n", (ans+1)/2); }