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;
}