求哪几条边是桥,用Tarjan算法,注意重边的处理。
#include<cstdio> #include<cstring> #include<cmath> #include<vector> #include<algorithm> using namespace std; const int maxn=10000+10; //结点数量 const int Maxn=2*100000+10; //边的数量 int low[maxn]; int dfn[maxn]; struct Edge { int from; int to; int id; int ans;//ans为1,表示这条边是割边 } edge[Maxn]; vector<int>G[maxn]; int Ans[Maxn]; int N,M;//N个结点,M条边 int tmpdfn; int tot; void init() { for(int i=0; i<maxn; i++) G[i].clear(); memset(low,0,sizeof(low)); memset(dfn,0,sizeof(dfn)); low[1]=dfn[1]=1; tmpdfn=0; tot=0; } int dfs(int u,int id) { tmpdfn++; int lowu=dfn[u]=tmpdfn; for(int i=0; i<G[u].size(); i++) { int B=G[u][i]; if(!dfn[edge[B].to]) { int lowv=dfs(edge[B].to,edge[B].id); lowu=min(lowu,lowv); if(lowv>dfn[u]) edge[B].ans=1; } else if(dfn[edge[B].to]) { if(edge[B].id/2==id/2) continue; lowu=min(lowu,dfn[edge[B].to]); } } low[u]=lowu; return lowu; } void AddEdge(int u,int v) { edge[tot].from=u; edge[tot].to=v; edge[tot].id=tot; edge[tot].ans=0; G[u].push_back(tot); tot++; edge[tot].from=v; edge[tot].to=u; edge[tot].id=tot; edge[tot].ans=0; G[v].push_back(tot); tot++; } int main() { int T_T; scanf("%d",&T_T); while(T_T--) { scanf("%d%d",&N,&M); init(); for(int i=0; i<M; i++) { int u,v; scanf("%d%d",&u,&v); AddEdge(u,v); } dfs(1,-1); int ans=0; for(int i=0; i<2*M; i++) if(edge[i].ans) { Ans[ans]=edge[i].id/2+1; ans++; } printf("%d ",ans); for(int i=0; i<ans; i++) { if(i<ans-1) printf("%d ",Ans[i]); else printf("%d ",Ans[i]); } if(T_T>=1) printf(" "); } return 0; }