uva 10972 RevolC FaeLoN

双连通分量

题意:一个无向图要添加多少条边才能使其变为边双连通分量,和  poj 3352 Road Construction 几乎一样的题目,不同的是,poj这题,原图是保证连通的,这题是不连通的,过程完全一样,只是最后计算答案的公式不同.所以题目分析就不写了,直接看poj那题吧,其实这题也是模板题,懂双连通分量的知识的话,并不需要看分析

poj那题,缩点后不会出现孤立点,因为整个图连通的,所以只要找到缩点后的叶子个数就可以了,所以是(leaf+1)/2

对于这题,因为图不连通,可能出现缩点后的孤立点。首先看缩点后的图,可能是一块一块的,对于点数超过1的块,和poj那题是一样的,只要找到叶子,所以没找到一个叶子就计数1,然后连接叶子,就能先把这块变成一个边双连通分量。对于那些只有一个点的块,要向其他块连至少2条边才能保证边双连通,所以找到缩点后有多少个孤立点,这些孤立点要计数2,表示连两条边

最后答案就是(A + 1 + B*2)/2  , A表示有多少个叶子,B表示有多少个孤立点

如果原图就是个边双连通分量,不需要加任何边,输出0

 

同样给出两个代码,第1个代码是简化了tarjan

#include <iostream>

#include <cstdio>

#include <cstring>

#include <stack>

#include <vector>

using namespace std;

#define N 1010



int n,tot;

int dfn[N],low[N],vis[N],de[N],dcnt,bcnt;

vector<int>e[N];



void init()

{

    dcnt = bcnt = 0;

    for(int i=1; i<=n; i++)

    {

        dfn[i] = 0;

        e[i].clear();

        vis[i] = de[i] = 0;

    }

}



void dfs(int u ,int fa)

{

    dfn[u] = low[u] = ++dcnt;

    vis[u] = 1;

    for(int i=0; i<e[u].size(); i++)

    {

        int v = e[u][i];

        if(v == fa) continue;

        if(!vis[v]) //树边

        {

            dfs(v,u);

            low[u] = min(low[u] , low[v]);

            if(low[v] > dfn[u]) //找到一个桥,新增一个连通分量

                bcnt++;

        }

        else if(vis[v] == 1) //后向边

            low[u] = min(low[u] , dfn[v]);

    }

}



void solve()

{

    for(int i=1; i<=n; i++)

        if(!vis[i])

        {

            dfs(i,-1);

            bcnt++;

        }

    if(bcnt == 1) //整个图本身就是个双连通分量

    { cout << 0 << endl; return ; }



    bool used[N];

    memset(used,false,sizeof(used));

    for(int i=1; i<=n; i++)

    {

        if(e[i].size() == 0) //孤立点,它自身形成一个连通分量

        { used[low[i]] = true ; continue; }



        for(int j=0; j<e[i].size(); j++)

        {

            int u = i;

            int v = e[i][j];

            used[low[u]] = used[low[v]] = true;

            if(low[u] != low[v]) //不同的连通分量

                de[low[u]]++;

        }

    }



    int res = 0;

    for(int i=1; i<=n; i++)  //扫描缩点后每个点的度

        if(used[i] && de[i] == 0) //度为0即孤立点

            res += 2;

        else if(de[i] == 1) //叶子

            res++;

    cout << (res+1)/2 << endl;

}



int main()

{

    while(cin >> n >> tot)

    {

        init();

        while(tot--)

        {

            int u,v;

            cin >> u >> v;

            e[u].push_back(v);

            e[v].push_back(u); 

            //偷懒直接用vector建图不用静态链表了

        }

        solve();

    }

    return 0;

}

 

 

模板,找到所有的桥

#include <iostream>

#include <cstdio>

#include <cstring>

#include <stack>

#include <vector>

#include <utility>

using namespace std;

#define N 1010



int n,tot;

int dfn[N],low[N],ins[N],belong[N],de[N],dcnt,bcnt;

vector<int>e[N];

stack<int>sta;

typedef pair<int,int> pii;

vector<pii>bridge;



void init()

{

    dcnt = bcnt = 0;

    while(!sta.empty()) sta.pop();

    bridge.clear();

    for(int i=1; i<=n; i++)

    {

        dfn[i] = 0;

        e[i].clear();

        ins[i] = de[i] = 0;

    }

}



void dfs(int u ,int fa)

{

    sta.push(u); ins[u] = true;

    dfn[u] = low[u] = ++dcnt;

    for(int i=0; i<e[u].size(); i++)

    {

        int v = e[u][i];

        if(v == fa) continue;

        if(!dfn[v]) //树边

        {

            dfs(v,u);

            low[u] = min(low[u] , low[v]);

            if(low[v] > dfn[u]) //

            {

                bridge.push_back(make_pair(u,v));

                ++bcnt;

                while(true)

                {

                    int x = sta.top();

                    sta.pop(); ins[x] = 0;

                    belong[x] = bcnt;

                    if(x == v) break;

                }

            }

        }

        else if(ins[v]) //后向边

            low[u] = min(low[u] , dfn[v]);

    }

}



void solve()

{

    for(int i=1; i<=n; i++)

        if(!dfn[i])

        {

            dfs(i,-1);

            bcnt++;

            while(!sta.empty())

            {

                int x = sta.top();

                sta.pop(); ins[x] = 0;

                belong[x] = bcnt;

                if(x == i) break;

            }

        }

    if(bcnt == 1)

    {cout << 0 << endl; return ;}

    

    for(int i=0; i<bridge.size(); i++) //取出所有的桥

    {

        int u = bridge[i].first;

        int v = bridge[i].second;

        de[belong[u]]++;

        de[belong[v]]++;

    }

    int res = 0;

    for(int i=1; i<=bcnt; i++)

        if(de[i] == 0)      res += 2;

        else if(de[i] == 1) res++;



    cout << (res+1)/2 << endl;

}



int main()

{

    while(cin >> n >> tot)

    {

        init();

        while(tot--)

        {

            int u,v;

            cin >> u >> v;

            e[u].push_back(v);

            e[v].push_back(u);

        }

        solve();

    }

    return 0;

}

 

你可能感兴趣的:(uva)