zoukankan      html  css  js  c++  java
  • 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
  • 相关阅读:
    ncover
    bash
    .net framework 工具
    keePass
    jersey
    i-jetty
    如何查看set环境变量的更改
    C语言丨如果你不是程序员,绝对看不懂这三个符号!(= 和==、!=)
    忘记 root 密码怎么办?教你4种使用MySQL方式修改密码!(超实用)
    一线城市容不下肉体,二三线城市安放不了灵魂,程序员何处为家?
  • 原文地址:https://www.cnblogs.com/zhazhaacmer/p/8393391.html
Copyright © 2011-2022 走看看