ZOJ2588 Burning Bridges(割边模板)
题目要输出一个无向图的所有割边。用Tarjan算法:
一遍DFS,构造出一颗深度优先生成树,在原无向图中边分成了两种:树边(生成树上的边)和反祖边(非生成树上的边)。
顺便求出每个结点的DFS序dfn[u] 和 每个结点能沿着它和它的儿子的返祖边达到的结点最小的DFS序low[u]。
一条边(u,v)是割边当且仅当——
- low[v]>dfn[u]
注意具体实现时,无向图的边在邻接表中有正反两条边,那么如果一条边是树边了,另一条边不应该是反祖边,要忽略。
1 #include<cstdio> 2 #include<cstring> 3 #include<algorithm> 4 using namespace std; 5 #define MAXM 222222 6 #define MAXN 11111 7 struct Edge{ 8 int v,next; 9 bool tag; 10 }edge[MAXM]; 11 int NE,head[MAXN]; 12 void addEdge(int u,int v){ 13 edge[NE].v=v; edge[NE].next=head[u]; edge[NE].tag=0; 14 head[u]=NE++; 15 } 16 int dn,dfn[MAXN],low[MAXN],res[MAXM],resn; 17 void dfs(int u){ 18 dfn[u]=low[u]=++dn; 19 for(int i=head[u]; i!=-1; i=edge[i].next){ 20 if(edge[i].tag) continue; 21 int v=edge[i].v; 22 if(dfn[v]){ 23 low[u]=min(low[u],dfn[v]); 24 continue; 25 } 26 edge[i].tag=edge[i^1].tag=1; 27 dfs(v); 28 low[u]=min(low[u],low[v]); 29 if(low[v]>dfn[u]) res[resn++]=(i>>1)+1; 30 } 31 } 32 int main(){ 33 int t,n,m,a,b; 34 scanf("%d",&t); 35 while(t--){ 36 scanf("%d%d",&n,&m); 37 NE=0; 38 memset(head,-1,sizeof(head)); 39 while(m--){ 40 scanf("%d%d",&a,&b); 41 addEdge(a,b); addEdge(b,a); 42 } 43 resn=dn=0; 44 memset(dfn,0,sizeof(dfn)); 45 dfs(1); 46 printf("%d\n",resn); 47 sort(res,res+resn); 48 for(int i=0; i<resn; ++i){ 49 if(i) putchar(' '); 50 printf("%d",res[i]); 51 } 52 if(resn) putchar('\n'); 53 if(t) putchar('\n'); 54 } 55 return 0; 56 }