/*
*State: ZOJ2588 530 MS    12788 KB    GNU C++
*题目大意:
*        给出一个无向图,输入n(表示n个定点,1~n), m(m条边,有重边),
*        (2 <= N <= 10 000, 1 <= M <= 100 000),求这个无向图中的桥,
*        并输出桥属于输入中边的id.
*解题思路:
*        知道求割点与求割边是很相似的,自己用笔模拟一下就知道,如果
*        存在low[v] > dfn[u].那么uv就是割边。看似与割点异常类似,但是
*        用了原始的求割点的tarjan敲了几遍后发现,不行。因为求割点的时
*        候由于条件是low[v] >= dfn[u],所以它可能回溯回自己的父亲节点,
*        然后就更新了自己的low[v].之后求割边的条件就实现不出来了。
*
*        发现了这个问题之后,就修改了tarjan算法,把参数由一个当前节点
*        改为2个,一个父亲结点,一个它自己,然后搜。将一个节点的所有孩
*        子节点都搜一遍,之后再判断,只要dfn[n] == low[n],就说明n跟它
*        的父亲节点构成的边是割边。为什么?因为dfn[n] == low[n],就说明
*        当前节点n的所有孩子节点都最多只能到达当前节点n的孩子节点。也就
*        是说n跟它的father是关节边。
*
*        ps:为什么求割点是把判断放在循环内,求割边要放在循环外(其实放
*        循环外面也可以,但是要注意回溯判断的不同,要修改根节点的情况)。
*        用笔模拟下即可。该题有重边,我先把它当无重边算,之后在判断割边
*        的时候判断下是否为重边即可。
*/
View Code
#include <iostream>
#include <vector>
#include <cstdio>
#include <algorithm>
#include <utility>
#include <cstring>
using namespace std;

typedef struct _node
{
    int v, id, num;
    _node():num(0) {};
}N;

const int MAX = 10005;
vector<N> vec[MAX];
int dfn[MAX], low[MAX], step, id;
int ans[MAX * 10], cnt;

void addEdge(int u, int v)
{
    bool flag = false;
    for(unsigned i = 0; i < vec[u].size(); i++)
    {
        if(vec[u][i].v == v)
        {
            flag = true;
            vec[u][i].num++;
            for(unsigned j = 0; j < vec[v].size(); j++)
            {
                if(vec[v][j].v == u)
                {
                    vec[v][j].num++;
                    break;
                }
            }
            id++;
            break;
        }
    }
    if(flag == false)
    {
        N tmp;
        tmp.v = v, tmp.id = id++;
        tmp.num = 1;
        vec[u].push_back(tmp);
        tmp.v = u;
        vec[v].push_back(tmp);
    }
}

void tarjan(int father, int n)
{
    dfn[n] = low[n] = ++step;
    for(unsigned i = 0; i < vec[n].size(); i++)
    {
        int son = vec[n][i].v;
        if(dfn[son] == -1)
        {
            tarjan(n, son);
            low[n] = min(low[n], low[son]);
        }
        else if(son != father)
            low[n] = min(low[n], dfn[son]);
    }

    if(dfn[n] == low[n])
    {
        int son = n;
        n = father;
        for(unsigned k = 0; k < vec[n].size(); k++)
        {
            if(son == vec[n][k].v)
            {
                if(vec[n][k].num == 1)
                {
                    ans[cnt++] = vec[n][k].id;
                }
                break;
            }
        }
    }
}

void init()
{
    id = 1;
    step = cnt = 0;
    for(int i = 0; i < MAX; i++)
    {
        vec[i].clear();
        dfn[i] = low[i] = -1;
    }
}

int main(void)
{
#ifndef ONLINE_JUDGE
    //freopen("in.txt", "r", stdin);
#endif

    int cas;
    scanf("%d", &cas);
    while(cas--)
    {
        init();
        int n, m;
        scanf("%d %d", &n, &m);
        for(int i = 0; i < m; i++)
        {
            int u, v;
            scanf("%d %d", &u, &v);
            addEdge(u, v);
        }
        dfn[1] = low[1] = ++step;
        tarjan(1, 1);

        printf("%d\n", cnt);
        if(cnt)
        {
            sort(ans, ans + cnt);
            printf("%d", ans[0]);
            for(int i = 1; i < cnt; i++)
            {
                printf(" %d", ans[i]);
            }
            printf("\n");
        }
        if(cas)
            printf("\n");
    }
    return 0;
}
posted on 2012-08-18 09:31  cchun  阅读(335)  评论(0编辑  收藏  举报