题目链接:
http://www.lightoj.com/volume_showproblem.php?problem=1026
题目大意:
给出一个无向图(不一定连通),求割边。
解题思路:
求割边的方法跟求强连通分量类似都是通过DFS来实现的。记录dfn[u],low[u]为u第一次访问的时间、可达到的最早的结点。dfs的过程中,对于边u->v,如果low[v]>dfn[u]那么u->v是割边,因为v到达的最早的结点也在u点之后,所以去掉u->v这条边后,u和它之前的点就不可达v了。
代码:
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
pair<int,int>side[200001];
int low[10001],dfn[10001],isbridge[200001],t,node[10001],top,cnt;
pair<int,int>ans[200001];
int n,m,ans_top;
void dfs(int u,int fa){
low[u]=dfn[u]=t++;
int v;
for(int i=node[u];i!=-1;i=side[i].second){
v=side[i].first;
if(!dfn[v]){
dfs(v,u);
low[u]=min(low[u],low[v]);
if(low[v]>dfn[u]){
isbridge[i]=true;
cnt++;
}
}else if(dfn[v]<dfn[u]&&v!=fa){
low[u]=min(low[u],dfn[v]);
}
}
}
void tarjan(){
memset(dfn,0,sizeof(dfn));
t=1;
for(int i=0;i<n;i++){
if(!dfn[i])dfs(i,i);
}
}
int main(){
int T;
scanf("%d",&T);
int ca=1;
while(T--){
top=0;
cnt=0;
memset(node,-1,sizeof(node));
printf("Case %d:\n",ca++);
scanf("%d",&n);
for(int i=0;i<n;i++){
int u,k;
scanf("%d (%d)",&u,&k);
for(int j=0;j<k;j++){
int v;
scanf("%d",&v);
side[top]=make_pair(v,node[u]);
isbridge[top]=false;
node[u]=top++;
}
}
tarjan();
printf("%d critical links\n",cnt);
ans_top=0;
for(int u=0;u<n;u++){
for(int i=node[u];i!=-1;i=side[i].second){
int v=side[i].first;
if(isbridge[i])ans[ans_top++]=make_pair(min(u,v),max(u,v));
}
}
sort(ans,ans+ans_top);
for(int i=0;i<ans_top;i++){
printf("%d - %d\n",ans[i].first,ans[i].second);
}
}
}