題目連接:http://acm.hdu.edu.cn/showproblem.php?pid=3394php
題目大意:
給定一個無向圖,若是從一個點出發通過一些點和邊能回到該點自己,那麼一路走過來的這些點和邊的集合就是一個環。
一個公園中有 n 個景點,景點之間經過無向的道路來鏈接,若是至少兩個環公用一條路,路上的遊客就會發生衝突;若是一條路不屬於任何的環,這條路就不必修。
問,有多少路沒必要修,有多少路會發生衝突?c++
解題思路:
每個連通塊中,若是邊數大於點數,這個塊中全部的邊所有是衝突邊。
全部橋爲不須要修建的路。spa
實現代碼以下:code
#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\n", bridge_num, crash_num); } return 0; }