• HDU4738【杭州网赛、判桥】


    刚拿到这道题时挺有思路,无奈平日里只敲过找割顶的代码,判桥的代码当时自己也没仔细敲。

    当时一把泪啊,忽然感觉自己的图论才只是刚搞了个起步啊哭。。

    题目有神坑。    就是先判是否连通,不连通直接输出0;

                                还有一个比较坑的是有重边的情况,那这样就有重边的两点之间就不可能存在桥。

                                再就是桥上无士兵把守也要派一个人去炸。

                                。。。

                                

                               

    #include <iostream>
    #include <cstdio>
    #include <cstring>
    #include <vector>
    #include <algorithm>
    using namespace std;
    
    const int maxn = 1500;
    int dfs_clock, current_clock, ans, current_cc;
    int adj[maxn][maxn], iscut[maxn], vis[maxn], pre[maxn], low[maxn];
    vector<int> G[maxn];
    int n, m, a, b, c, INF = 10000000;
    
    void dfs(int u)
    {
        vis[u] = 1;
        //PREVISIT(u); 访问u之前的操作
        for(int i = 0; i < G[u].size(); i++)
        {
            int v = G[u][i];
            if(!vis[v]) dfs(v);
        }
        //POSTVISIT(u); 访问结点u之后的操作
    }
    
    void find_cc()  //给连通分量标号
    {
        current_cc = 0;
        memset(vis, 0, sizeof(vis));
        for(int u = 1; u <= n; u++) if(!vis[u])
        {
            current_cc++;
            dfs(u);
        }
    }
    
    int dfs_bridge(int u,int fa) //u在dfs树中的父结点是fa
    {
        int lowu = pre[u] = ++dfs_clock;
        int child = 0;    //子结点数目
        for(int i = 0; i < G[u].size(); i++)
        {
            int v = G[u][i];
            if(!pre[v])   //没有访问过v
            {
                child++;
                int lowv = dfs_bridge(v, u);
                lowu = min(lowu, lowv);
                if(lowv >= pre[u])
                {
                    iscut[u] = true;   //割点判断
                    if(lowv > pre[u] && adj[u][v] != -2) //桥的判断可以相应灵活处理
                       ans = min(ans, adj[u][v]);
                }
            }
            else if(pre[v] < pre[u] && v != fa)
                lowu = min(lowu, pre[v]);  //用反向边更新u的low函数
        }
        if(fa < 0 && child == 1)
        {
            // 但是不用加是否单独判桥的判断?
            iscut[u] = 0;  //应该是避免单结点判桥、割顶的情况吧
        }
        low[u] = lowu;
        return lowu;
    }
    
    void init()
    {
        memset(pre, 0, sizeof(pre));
        memset(iscut, 0, sizeof(iscut));
        memset(adj, -1 ,sizeof(adj));
        for(int i = 0; i <= n; i++)
            G[i].clear();
    }
    
    int main()
    {
        while(scanf("%d%d",&n, &m) != EOF)
        {
            if(!n && !m) break;
            init();
            while(m--)
            {
                scanf("%d%d%d", &a, &b, &c);
                if(adj[a][b] == -1)
                {
                    G[a].push_back(b);
                    G[b].push_back(a);
                    adj[a][b] = c;
                    adj[b][a] = c;
                }
                else // 两点之间有两条边肯定不可能是桥
                {
                   adj[a][b] = -2;
                   adj[b][a] = -2;
                }
            }
    
            ans = INF;
            dfs(1);  find_cc();
            //printf("~%d
    ",current_cc);
            if(current_cc >= 2) { printf("0
    "); continue;}
            else dfs_bridge(1, -1);
            if(ans == 0) printf("1
    ");
            else if(ans == INF ) printf("-1
    ");
            else printf("%d
    ", ans);
        }
        return 0;
    }
    


     

  • 相关阅读:
    怎么把共享文件夹显示在我的电脑
    window时间同步机制的简单介绍
    向指定服务器的指定端口发送UDP包
    窜口通信-读取时间码
    窜口通信-发送时间码
    回环网卡通信
    简单的TCP接受在转发到客户端的套接口
    国内能用的NTP服务器及和标准源的偏差值
    简单的UDP接受程序
    TCP包服务器接受程序
  • 原文地址:https://www.cnblogs.com/james1207/p/3324888.html
Copyright © 2020-2023  润新知