ZOJ

tarjan求桥。

当e(u,v), low[v]>dfn[u],e(u,v)为桥。

双向边注意规定父亲和儿子的关系。

若有重边,一定不是桥。可以删除重边,或者换一种方式。

每个点记录更新到它的父亲边fa[i],若点u更新到v,则不能用dfn[u]更新low[v];之后若dfn[x]==low[x],则fa[i]为桥。

第二种写法的代码:

zoj的格式要求贼坑。。

#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<cmath>
#include<queue>
#include<vector>
typedef long long LL;
using namespace std;
const int maxn=10000+299;
const int maxm=100000*2+299;
int T,n,m,x,y,fir[maxn],nxt[maxm],to[maxm],fa[maxn],cc,cut[maxm],dfn[maxn],id[maxm],low[maxn],dfs_clock,ecnt;
void add(int x,int y,int tot) { 
    nxt[++ecnt]=fir[x]; fir[x]=ecnt; to[ecnt]=y; id[ecnt]=tot;
    nxt[++ecnt]=fir[y]; fir[y]=ecnt; to[ecnt]=x; id[ecnt]=tot;
}
void clear() {
    memset(fir,0,sizeof(fir));
    memset(dfn,0,sizeof(dfn));
    memset(low,0,sizeof(low));
    memset(cut,0,sizeof(cut));
    memset(fa,0,sizeof(fa)); ecnt=0;
    dfs_clock=0;
}
void tarjan(int x) {
    dfn[x]=low[x]=++dfs_clock;
    for(int i=fir[x];i;i=nxt[i]) {
        if(!dfn[to[i]]) {
            fa[to[i]]=i;
            tarjan(to[i]);
            low[x]=min(low[x],low[to[i]]);
        }
        else if(id[fa[x]]!=id[i]) low[x]=min(low[x],dfn[to[i]]);
    }
    if(fa[x]&&dfn[x]==low[x]) {
        cc++; 
        cut[id[fa[x]]]=1;
    }
}
int main()
{
    scanf("%d",&T);
    while(T) {
        clear();
        scanf("%d%d",&n,&m);
        for(int i=1;i<=m;i++) {
            scanf("%d%d",&x,&y);
            add(x,y,i);    
        }
        for(int i=1;i<=n;i++)
            if(!dfn[i]) tarjan(i);
        printf("%d
",cc);
        for(int i=1;i<=m;i++) 
            if(cut[i]) { cc--; if(cc) printf("%d ",i); else printf("%d
",i);}
        --T;
        if(T) printf("
");
    }
    return 0;
}
View Code
原文地址:https://www.cnblogs.com/Achenchen/p/7569717.html