hdu3394--Railway(点的双连通分量)
一个公园中有 n 个景点,景点之间通过无向的道路来连接,如果至少两个环公用一条路,路上的游客就会发生冲突;如果一条路不属于任何的环,这条路就没必要修
问,有多少路不必修,有多少路会发生冲突
每一个连通块中,如果边数大于点数,这个块中所有的边全部是冲突边。
所有桥为不需要修建的路。
通过这题学习点的双连通分量怎么求。强连通和双连通的题就做到这吧。
#include <bits/stdc++.h> using namespace std; const int M = 200010; const int N = 10010; struct Edge { int from, to; int next; } edge[M]; int head[N]; int cnt_edge; void add_edge(int u, int v) { edge[cnt_edge].from = u; edge[cnt_edge].to = v; edge[cnt_edge].next = head[u]; head[u] = cnt_edge++; } int dfn[N]; int idx; int low[N]; stack<Edge> stk; set<int> bcc; int cut; // 桥的数量 int ans; // 冲突边数量 int m, n; void dfs(int u, int pre) { dfn[u] = low[u] = ++idx; for (int i = head[u]; i != -1; i = edge[i].next) { int v = edge[i].to; if (v == pre) continue; if (!dfn[v]) { stk.push(edge[i]); dfs(v, u); low[u] = min(low[u], low[v]); if (low[v] >= dfn[u]) // 割点 { Edge tmp; int cnt = 0; bcc.clear(); do { cnt++; tmp = stk.top(); stk.pop(); bcc.insert(tmp.from); bcc.insert(tmp.to); } while (tmp.from != u || tmp.to != v); if (cnt > bcc.size()) ans += cnt; } if (low[v] > dfn[u]) ++cut; } else if (dfn[v] < dfn[u]) { stk.push(edge[i]); low[u] = min(low[u], dfn[v]); } } } void init() { memset(head, -1, sizeof head); memset(dfn, 0, sizeof dfn); ans = cut = cnt_edge = idx = 0; } int main() { while (~scanf("%d%d", &n, &m)) { if (n == 0 && m == 0) break; int u, v; init(); for (int i = 0; i < m; ++i) { scanf("%d%d", &u, &v); add_edge(u, v); add_edge(v, u); } for (int i = 1; i <= n; ++i) if (!dfn[i]) dfs(i, -1); printf("%d %d\n", cut, ans); } return 0; }