poj 3177 Redundant Paths

双连通分量

题意:给一个无向图,问要添加多少条边形成边双连通分量。注意图一开始是连通的,所以只要从一个点开始dfs一次就行了,另外这图有重边,(1,2)(2,1)这样,则1,2就形成了一个边双连通分量。

之前写的求边双连通分量的代码不能处理重边,但是要修改过来其实挺简单的。重边无非是遇到一个问题,从u走到v,按一般的做法,是不能从v回到u的,即不能马上就回到它父亲节点去(其实指的是不能重复走这条边,这条边虽然是无向边但是只能走一次),但是有了重边后,是可以马上回到它父亲处的,只不过走的是另一条边。所以我们可以标记哪些边用过了,每条边只能用一次,用过一次后不能再用。而且别忘了,建图的时候,无向边是分成两条有向边来保存的,所以当一条有向边被使用后,它对应的另一条反边也不能使用了,要一同标记(这样才起到了每条无向边只能走一次的效果),标记的方法很常用,e[k].used = e[k^1].used = 1;  神奇的位运算

然后这个方格其实是个更好的方法,另外这样的代码,是能够同时处理有重边和无重边的情况的,所以就这样运行一下tarjan就能出结果

 

#include <iostream>
#include <vector>
#include <utility>
#include <stack>
#include <cstdio>
#include <cstring>
using namespace std;
#define N 5010
#define M 10010

int n,tot;
int head[N],dfn[N],low[N],belong[N],ins[N],de[N],dcnt,bcnt;
typedef pair<int,int>pii;
struct edge
{
    int u,v,used,next;
}e[2*M];
vector<pii>bridge;
stack<int>sta;

void add(int u , int v , int k)
{
    e[k].u = u; e[k].v = v; e[k].used = 0;
    e[k].next = head[u]; head[u] = k++;
    u = u^v; v = u^v; u = u^v;
    e[k].u = u; e[k].v = v; e[k].used = 0;
    e[k].next = head[u]; head[u] = k++;
}

void dfs(int u ,int fa)
{
    dfn[u] = low[u] = ++dcnt;
    sta.push(u); ins[u] = 1;
    for(int k=head[u]; k!=-1; k=e[k].next)
        if(!e[k].used)
        {
            e[k].used = e[k^1].used = 1;
            int v = e[k].v;
            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] = false;
                        belong[x] = bcnt;
                        if(x == v) break;
                    }
                }
            }
            else if(ins[v]) //后向边
                low[u] = min(low[u] , dfn[v]);
        }
}

void solve()
{
    bridge.clear();
    while(!sta.empty()) sta.pop();
    memset(ins,0,sizeof(ins));
    memset(dfn,0,sizeof(dfn));
    memset(de,0,sizeof(de));
    dcnt = bcnt = 0;
    dfs(1,-1);
    ++bcnt;
    while(!sta.empty())
    {
        int x = sta.top();
        sta.pop(); ins[x] = 0;
        belong[x] = bcnt;
    }

//    for(int i=1; i<=n; i++)
//        cout << i << "[" << low[i] << "]" << endl;

    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 leaf = 0;
    for(int i=1; i<=bcnt; i++)
        if(de[i] == 1)
            leaf++;
    cout << (leaf+1)/2 << endl;
}

int main()
{
    while(cin >> n >> tot)
    {
        tot *= 2;
        memset(head,-1,sizeof(head));
        for(int i=0; i<tot; i+=2)
        {
            int u,v;
            cin >> u >> v;
            add(u,v,i);
        }
        solve();
    }
    return 0;
}

 

posted @ 2013-05-19 17:25  Titanium  阅读(270)  评论(0编辑  收藏  举报