• 图论训练之八


    http://poj.org/problem?id=3177

    题目描述

    给一个连通图,问最少加几条边可以得到边双连通图。

    分析:

    模板题,复习一下

    tarjan双向边缩点,再找叶子结点(即出度为1的点)

    其实本题可以不用缩点,只用维护low数组就行,

    只要low数组的值相等,就是属于同一连通块

    为什么要找叶子结点呢?

    结论:一个无向图通过加边得到边双联通图至少要(叶子结点数目+1)/2

    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #include<vector>
    using namespace std;
    const int MAXN = 5010;
    vector<int>edge[MAXN];
    int n, m;
    int low[MAXN], dfn[MAXN], tmpdfn, in[MAXN];
    int min( int a, int b ){return a<b ?a:b;}
    void init()
    {
        int i;
        for( i = 1; i <= n ; i++ )edge[i].clear();
        memset(in,0,sizeof(int)*(n+1));
        memset(dfn,0,sizeof(dfn));
        tmpdfn=0;
    }
    void tarjan( int u, int p )
    {
        int i, v, size;
        low[u] = dfn[u] = ++tmpdfn;
        size = edge[u].size();
        for( i = 0; i < size; i++ )
        {
            v = edge[u][i];
            if( !dfn[v] )
                tarjan( v, u ), low[u] = min( low[u], low[v] );
            else if( v != p )low[u] = min( low[u], dfn[v] );
        }
    }
    int count()
    {
        int cnt, u, v, i, size;
        cnt = 0;
        for( u = 1; u <= n; u++ )
        {
            size = edge[u].size();
            for( i = 0; i < size; i++ )
            {                            // low 相同的节点,归属于同一双连通分量
                v = edge[u][i];
                if( low[v] != low[u] )in[low[u]]++;
            }
        }
        for( u = 1; u <= n; u++ )if( in[u] == 1 )
            cnt++;
        return cnt;
    }
    int main()
    {
        int i, j, u, v, flag, size;
        scanf( "%d%d", &n, &m );
        init();
        for( i = 0; i < m ; i++ )
        {
            scanf( "%d%d", &u, &v );
            flag = 0;    size = edge[u].size();
            for( j = 0; j < size; j++ )
                if( edge[u][j] == v ){
                    flag = 1; break;
                }
            if( flag )continue;
            edge[u].push_back( v );
            edge[v].push_back( u );
        }
        tarjan( 1, -1 );
        printf( "%d
    ", ( count() + 1 ) >> 1 );
        return 0;
    }
    
  • 相关阅读:
    WDK中出现的特殊代码
    敏捷是怎样炼成的
    推荐一个非常好玩的falsh游戏
    软件安全技术
    J2EE的昨天,今天,明天
    Java打印程序设计
    关于父亲
    xml发展历史和用途
    CRM与ERP整合的六个切入点
    SEO(搜索引擎最佳化)简介
  • 原文地址:https://www.cnblogs.com/wzxbeliever/p/11643790.html
Copyright © 2020-2023  润新知