zoj 2588 Burning Bridges

有向图强连通分量的Tarjan算法:http://www.byvoid.com/blog/scc-tarjan/

/*
zoj 2588    求割边
Tarjan算法。第一次写tarjan,完全学习别人写的。
注意点:
1.必须变成有向图存储,对于一条无向边,从一个方向访问过,则另一个方向不能访问。
2.因为两点之间可能有多条边,重边必定不是割边,需标记。
3.临界表存储。
*/
#include <iostream>
#include <cstdio>
#include <string.h>
#include <algorithm>
#define N 10005
#define M 1000005
using namespace std;
int DFN[N],LOW[N],head[M],bridge[M],nbridge,k,num;
struct way
{
    int next,id,v,tag;
}w[M];

void inint()
{
    int i;
    k=1;    nbridge=0;  num=1;
    memset( head,0,sizeof(head) );
    memset( DFN,0,sizeof(DFN) );
    memset( LOW,0,sizeof(LOW) );
    memset( bridge,0,sizeof(bridge) );
}

void addedge( int a,int b,int id )
{
    int i;
    for( i=head[a];i;i=w[i].next )
        if( w[i].v==b ) break;
    if(i)
    {
        w[i].tag=1;
        return;
    }
    w[k].next=head[a];
    w[k].id=id;
    w[k].tag=0;
    w[k].v=b;
    head[a]=k;  k++;
}

void tarjan( int sta,int father )
{
    int i,v;
    DFN[sta]=LOW[sta]=++num;
    for( i=head[sta];i;i=w[i].next )
    {
        v=w[i].v;
        if( !DFN[v] )
        {
            tarjan( v,sta );
            LOW[sta]=min( LOW[sta],LOW[v] );
            if( DFN[sta]<LOW[v] && !w[i].tag )
                bridge[nbridge++]=w[i].id;
        }
        else if( v!=father ) LOW[sta]=min( LOW[sta],DFN[v] );
    }
}

int main()
{
    int T,m,n,i;
    int a,b;
    scanf( "%d",&T );
    while( T-- )
    {
        inint();
        scanf( "%d%d",&n,&m );
        for( i=0;i<m;i++ )
        {
            scanf( "%d%d",&a,&b );
            addedge( a,b,i+1 );
            addedge( b,a,i+1 );
        }
        tarjan( 1,-1 );
        printf("%d\n",nbridge);
        if(nbridge)
        {
            sort( bridge,bridge+nbridge );
            for(i=0;i<nbridge-1;i++)
                printf("%d ",bridge[i]);
            printf("%d\n",bridge[nbridge-1]);
        }
        if(T) printf("\n");
    }
    return 0;
}


你可能感兴趣的:(算法,存储)