您的位置:首页 > 其它

poj 3177 Redundant Paths (双连通)

2015-08-07 09:57 453 查看
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:

1 – 2: 1 –> 2 and 1 –> 6 –> 5 –> 2

1 – 4: 1 –> 2 –> 3 –> 4 and 1 –> 6 –> 5 –> 4

3 – 7: 3 –> 4 –> 7 and 3 –> 2 –> 5 –> 7

Every pair of fields is, in fact, connected by two routes.

看ζёСяêτ
- 小優YoU 的解析很明白的哦,讲述的太明白了

少在缩点树上增加多少条树边,使得这棵树变为一个双连通图”。
首先知道一条等式:
若要使得任意一棵树,在增加若干条边后,变成一个双连通图,那么
至少增加的边数 =( 这棵树总度数为1的结点数 + 1 )/ 2

/article/1968984.html

#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
, dfn
, ft
, f
, eg
, Stack
;

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
 = {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);
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: