zoj2588-tarjan求桥/割边
tarjan求桥,算法流程详见核心代码:
1 void tarjan(int k){ 2 dfn[k]=low[k]=++cnt; 3 //fa[k]=(edge){f,0,fid}; 4 for(int i=head[k];i;i=e[i].nxt){ 5 int v=e[i].to; 6 if(!dfn[v]){ 7 fa[v]=e[i].id;//标记该边已走过,防止沿无向边返回 8 tarjan(v); 9 low[k]=min(low[v],low[k]); 10 }else 11 if(fa[k]!=e[i].id)low[k]=min(low[k],dfn[v]);//在不走无向边的情况下更新low 12 } 13 if(fa[k]&&low[k]==dfn[k])//若节点k的low=dfn则k在一个联通块中处于搜索树的顶部,那么节点k的父边一定为割边 14 ans[++na]=fa[k]; 15 }
模板题:zoj2588
题目大意:给出一个无向图,按顺序输出割边序号。
好久没用zoj,PE几次,若无割边要加个判断,以免多输出个0
1 #include<cstring> 2 #include<cstdio> 3 #include<algorithm> 4 #define foru(i,x,y) for(int i=x;i<=y;i++) 5 #define clr(x) memset(x,0,sizeof(x)) 6 using namespace std; 7 const int N=10100; 8 struct edge{int to,nxt,id;}e[210000]; 9 int head[N],dfn[N],low[N],ans[N],ne,na,cnt,n,m; 10 int fa[N]; 11 void add(int a,int b,int c){ 12 e[++ne]=(edge){b,head[a],c};head[a]=ne; 13 } 14 15 void tarjan(int k){ 16 dfn[k]=low[k]=++cnt; 17 //fa[k]=(edge){f,0,fid}; 18 for(int i=head[k];i;i=e[i].nxt){ 19 int v=e[i].to; 20 if(!dfn[v]){ 21 fa[v]=e[i].id;//标记该边已走过,防止沿无向边返回 22 tarjan(v); 23 low[k]=min(low[v],low[k]); 24 }else 25 if(fa[k]!=e[i].id)low[k]=min(low[k],dfn[v]);//在不走无向边的情况下更新low 26 } 27 if(fa[k]&&low[k]==dfn[k])//若节点k的low=dfn则k在一个联通块中处于搜索树的顶部,那么节点k的父边一定为割边 28 ans[++na]=fa[k]; 29 } 30 31 int main(){ 32 int T,u,v; 33 scanf("%d",&T); 34 while(T--){ 35 clr(e);clr(head);clr(dfn);clr(low);clr(fa);clr(ans); 36 ne=na=cnt=0; 37 scanf("%d%d",&n,&m); 38 foru(i,1,m){ 39 scanf("%d%d",&u,&v); 40 add(u,v,i);add(v,u,i); 41 } 42 foru(i,1,n) 43 if(!dfn[i])tarjan(i); 44 sort(ans+1,ans+1+na); 45 printf("%d\n",na); 46 if(na){ 47 foru(i,1,na-1)printf("%d ",ans[i]);printf("%d\n",ans[na]);} 48 if(T)printf("\n"); 49 } 50 return 0; 51 }