您的位置:首页 > 其它

ZOJ2588 Burning Bridges(割边模板)

2016-01-23 20:26 267 查看
题目要输出一个无向图的所有割边。用Tarjan算法:

一遍DFS,构造出一颗深度优先生成树,在原无向图中边分成了两种:树边(生成树上的边)和反祖边(非生成树上的边)。

顺便求出每个结点的DFS序dfn[u] 和 每个结点能沿着它和它的儿子的返祖边达到的结点最小的DFS序low[u]

一条边(u,v)是割边当且仅当——

low[v]>dfn[u]

注意具体实现时,无向图的边在邻接表中有正反两条边,那么如果一条边是树边了,另一条边不应该是反祖边,要忽略。

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
#define MAXM 222222
#define MAXN 11111
struct Edge{
int v,next;
bool tag;
}edge[MAXM];
int NE,head[MAXN];
void addEdge(int u,int v){
edge[NE].v=v; edge[NE].next=head[u]; edge[NE].tag=0;
head[u]=NE++;
}
int dn,dfn[MAXN],low[MAXN],res[MAXM],resn;
void dfs(int u){
dfn[u]=low[u]=++dn;
for(int i=head[u]; i!=-1; i=edge[i].next){
if(edge[i].tag) continue;
int v=edge[i].v;
if(dfn[v]){
low[u]=min(low[u],dfn[v]);
continue;
}
edge[i].tag=edge[i^1].tag=1;
dfs(v);
low[u]=min(low[u],low[v]);
if(low[v]>dfn[u]) res[resn++]=(i>>1)+1;
}
}
int main(){
int t,n,m,a,b;
scanf("%d",&t);
while(t--){
scanf("%d%d",&n,&m);
NE=0;
memset(head,-1,sizeof(head));
while(m--){
scanf("%d%d",&a,&b);
addEdge(a,b); addEdge(b,a);
}
resn=dn=0;
memset(dfn,0,sizeof(dfn));
dfs(1);
printf("%d\n",resn);
sort(res,res+resn);
for(int i=0; i<resn; ++i){
if(i) putchar(' ');
printf("%d",res[i]);
}
if(resn) putchar('\n');
if(t) putchar('\n');
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: