Light OJ

   原题链接

    无向连通图中,如果删除某边后,图变成不连通,则称该边为桥。

  也可以先用Tajan()进行dfs算出所有点 的low和dfn值,并记录dfs过程中每个 点的父节点;然后再把所有点遍历一遍, 看其low和dfn,满足dfn[ fa ]<low[ i ](0<i<=n, i 的 father为fa) —— 则桥为fa-i。 找桥的时候,要注意看有没有重边;有重边,则不是桥。

  另外,本题的题意及测试样例中没有重边,所以不用考虑重边。

  


带详细注释的题解:

#include<stdio.h>
#include<string.h>
#include<math.h>
#include<iostream>
#include<algorithm>
#include<stack>
#include<vector>
#define maxn 10010
using namespace std;
int dfn[maxn],low_link[maxn] ,Father[maxn];
//tarjan 算法的dfn ——在DFS过程中 的访问序号(也可以叫做开始时间
//tarjan 算法的low_link[i]——从i节点出发DFS过程中i下方节点所能到达的最早的节点的 开始时间
int bridgenum, Time ,n ;  //桥的总数,dfn时间戳,n为顶点数,
vector<int>G[maxn]; //定义图的邻接矩阵表
stack<int>st;
struct node{
    int u,v;
}bridge[maxn];  //整个图的桥的存储
bool cmp( node a,node b )
{
    if(a.u!=b.u)return a.u<b.u;
    else return a.v<b.v;
}
void init(){
    int i;
    for(i=0;i<=n;i++)  //初始化邻接表
        G[i].clear();
    bridgenum=0;Time=0;
    memset(dfn,0,sizeof(dfn));
    memset(low_link,0,sizeof(low_link));
    memset(Father,0,sizeof(Father));
}
void tarjan(int u,int fa)
{
    low_link[u]=dfn[u]=++Time;
    Father[u]=fa; //记录父节点
   // st.push(u);
    for(int i=0;i<(int)G[u].size();i++){
        int v=G[u][i];
        if(!dfn[v]){
            tarjan(v,u);
            low_link[u]=min(low_link[u],low_link[v]);
        }
        else if(v!=fa){  //不能连接到父节点!
            low_link[u]=min(low_link[u],dfn[v]);
        }
        else{
            //这种情况就是有重边的情况!不予处理,直接跳过!
        }
    }
}
void solve()
{
    for(int i=0;i<n;i++){
        if(!dfn[i])
            tarjan(i,-1);
    }
    int ans=0;
    for(int i=0;i<n;i++){
        int v=Father[i];
        if(dfn[v]<low_link[i]&&v!=-1){  //若v-i可以构成父节点
            bridge[ans].u=v; //桥的两条边
            bridge[ans].v=i;
            if(bridge[ans].u>bridge[ans].v)
                swap(bridge[ans].u,bridge[ans].v);
            ans++;
        }
    }
    sort(bridge,bridge+ans,cmp);
    printf("%d critical links
",ans);
    for(int i=0;i<ans;i++){
        printf("%d - %d
",bridge[i].u,bridge[i].v);
    }
}
int cal_num(char ch[]){
    int len=strlen(ch),s=0;
    for(int i=1;i<=len-2;i++){
        s=s*10+ch[i]-'0';
    }
    return s;
}
int main()
{
    int T,cas=0;
    scanf("%d",&T);
    while(T--)
    {
        init();
        char ch[10];
        int m ,u,v; //边数
        scanf("%d",&n);
        for(int i=1;i<=n;i++){
            scanf("%d%s",&u,ch);
            m=cal_num(ch);  //截取出数字存入m——边数
            for(int j=1;j<=m;j++){
                scanf("%d",&v);
                G[u].push_back(v);  //这里按单向边任意一边存储就可以了,毕竟是无向图!
                G[v].push_back(u);
            }
        }
        printf("Case %d:
",++cas);
        solve();
    }
    return 0;
}
View Code
原文地址:https://www.cnblogs.com/zhazhaacmer/p/8393391.html