题目链接: zoj 2588
题目大意: 在无向连通图中找桥,并且按序号输出
解题思路: Tarjan查找割边
数据中可能会出现重边,需要判断是否是重边
每次加入新的边,则枚举此顶点之前加入的边中是否存在另一点
low[vv]>dnf[u]是桥,low[vv]>=dnf[u]是割点
代码:
//Final Tarjan 找桥(割边) #include <stdio.h> #include <string.h> #include <stdlib.h> #include <algorithm> using namespace std; #define MAX 10005 #define MIN(a,b) a<b?a:b struct snode{ int to,next,num,m; }edge[MAX*20]; int visit[MAX],low[MAX],dnf[MAX],pre[MAX],ans[MAX],ansn,Index,n,high; void Add_edge(int a,int b,int mm) { int i; for(i=pre[a];i!=-1;i=edge[i].next) //遍历一遍之前加入该点的所有边 { if(edge[i].to==b) break; } if(edge[i].to==b) //记录重边,重边不是桥 edge[i].num++; else { edge[Index].to=b; edge[Index].m=mm; edge[Index].num=1; edge[Index].next=pre[a]; pre[a]=Index++; } } void Tarjan(int u,int father) { int v,vv; for(v=pre[u];v!=-1;v=edge[v].next) { vv=edge[v].to; if(!visit[vv]) { low[vv]=dnf[vv]=++high; visit[vv]=1; Tarjan(vv,u); low[u]=MIN(low[u],low[vv]); if(low[vv]>dnf[u]&&edge[v].num==1) //low[vv]>dnf[u]是桥,low[vv]>=dnf[u]是割点 { ans[ansn++]=edge[v].m; } } else if(vv!=father) //** { low[u]=MIN(low[u],dnf[vv]); } } } int main() { int m,i,t,a,b; scanf("%d",&t); while(t--) { Index=0; memset(pre,-1,sizeof(pre)); memset(visit,0,sizeof(visit)); memset(edge,0,sizeof(edge)); scanf("%d%d",&n,&m); for(i=0;i<m;i++) { scanf("%d%d",&a,&b); Add_edge(a,b,i+1); Add_edge(b,a,i+1); } low[1]=dnf[1]=visit[1]=high=1; //初始化 ansn=0; Tarjan(1,-1); sort(ans,ans+ansn); //序号排序输出 printf("%d\n",ansn); for(i=0;i<ansn-1;i++) { printf("%d ",ans[i]); } if(ansn) printf("%d\n",ans[ansn-1]); if(t) puts(""); } return 0; }