HDU3394 Railway 题解(边双连通分量)

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

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

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

实现代码如下:

#include 
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 stk;
set 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\n", bridge_num, crash_num);
    }
    return 0;
}

你可能感兴趣的:(HDU3394 Railway 题解(边双连通分量))