zoukankan      html  css  js  c++  java
  • HDU3394 Railway 题解(边双连通分量)

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=3394

    题目大意:
    给定一个无向图,如果从一个点出发经过一些点和边能回到该点本身,那么一路走过来的这些点和边的集合就是一个环。
    一个公园中有 n 个景点,景点之间通过无向的道路来连接,如果至少两个环公用一条路,路上的游客就会发生冲突;如果一条路不属于任何的环,这条路就没必要修。
    问,有多少路不必修,有多少路会发生冲突?

    解题思路:
    每一个连通块中,如果边数大于点数,这个块中所有的边全部是冲突边。
    所有桥为不需要修建的路。

    实现代码如下:

    #include <bits/stdc++.h>
    using namespace std;
    const int maxn = 10010, maxm = 100010;
    struct Edge {
        int u, v, nxt;
        Edge () {};
        Edge (int _u, int _v, int _nxt) { u = _u; v = _v; nxt = _nxt; }
    } edge[maxm<<1];
    int n, m, head[maxn], ecnt;
    void init() {
        memset(head, -1, sizeof(int)*(n+1));
        ecnt = 0;
    }
    void addedge(int u, int v) {
        edge[ecnt] = Edge(u, v, head[u]); head[u] = ecnt ++;
        edge[ecnt] = Edge(v, u, head[v]); head[v] = ecnt ++;
    }
    int dfn[maxn], low[maxn], cnt, bridge_num, crash_num;
    stack<int> stk;
    set<int> bcc;
    void tarjan(int u, int pre) {
        dfn[u] = low[u] = ++cnt;
        for (int i = head[u]; i != -1; i = edge[i].nxt) {
            int v = edge[i].v;
            if (v == pre) continue;
            if (!dfn[v]) {
                stk.push(i);
                tarjan(v, u);
                low[u] = min(low[u], low[v]);
                if (low[v] >= dfn[u]) {
                    int id;
                    int tmp_cnt = 0;
                    bcc.clear();
                    do {
                        tmp_cnt ++;
                        id = stk.top();
                        stk.pop();
                        bcc.insert(edge[id].u);
                        bcc.insert(edge[id].v);
                    } while (edge[id].u != u || edge[id].v != v);
                    if (tmp_cnt > bcc.size()) crash_num += tmp_cnt;
                }
                if (low[v] > dfn[u]) bridge_num ++;
            }
            else if (dfn[v] < dfn[u]) {
                stk.push(i);
                low[u] = min(low[u], dfn[v]);
            }
        }
    }
    int main() {
        while (~scanf("%d%d", &n, &m) && n) {
            init();
            memset(dfn, 0, sizeof(int)*(n+1));
            cnt = bridge_num = crash_num = 0;
            while (m --) {
                int a, b;
                scanf("%d%d", &a, &b);
                a ++; b ++;
                addedge(a, b);
            }
            for (int i = 1; i <= n; i ++)
                if (!dfn[i]) tarjan(i, -1);
            printf("%d %d
    ", bridge_num, crash_num);
        }
        return 0;
    }
    
  • 相关阅读:
    杭电 FatMouse' Trade
    Navicat Report Viewer 设置选项的问题
    用Beyond Compare精确查找文本内容的方法
    Beyond Compare表格比较详解
    Navicat Report Viewer 如何连接到 MySQL 数据库
    Navicat for MySQL 选项设置技巧详解
    Navicat 用什么方法检测 Oracle 数据库安全性
    有哪些好用的比较工具
    Beyond Compare文件比较有哪些方式
    Beyond Compare怎样修改差异文件夹
  • 原文地址:https://www.cnblogs.com/quanjun/p/12142268.html
Copyright © 2011-2022 走看看