題目: UVa - 315 - Network
題目說明
給一個所有點都有接通的無向圖,找出 Articulation Points ( 也叫 Cut Vertex、割點 ) 的數量。
Articulation Points 的定義:
- 對於根節點
root
,若其有兩棵或兩棵以上的子樹 ( degree >= 2 ),則該根節點 root
為割點。
- 對於非葉子節點
u
( 非根節點 ),若其 child 存在一個節點 v
或 v
的 descendant 沒有指向 u
的 proper ancestor ( 不包含 u
) 的 Back edge,則節點 u
為割點。
Input: 每組測資的第一行為一整數 N,表示有 N 個節點,若 N 為 0 代表結束,接下來最多 N 行為以空格隔開的數字,若為 0 則代表這筆測資結束,否則代表邊。如 5 1 2 3 4
表示有 ( 5, 1 )
、( 5, 2 )
、( 5, 3 )
、( 5, 4 )
這些邊。
Output: 輸出 Articulation Points 的數量。
解題思路
先讀取測資並建圖 ( 因為是無向圖,所以建雙向 ),之後 DFS,紀錄 DFS 時的序號及 low 值 ( 記錄節點 u
或 u
的子樹通過非父子邊追溯到最早的祖先節點 ( 即 DFS 的序號最小 ) ),之後根據割點的定義判斷並記錄數量即可。
參考解法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93
| #include <iostream> #include <algorithm> #include <vector> #include <string> #include <sstream> #include <functional>
using namespace std;
static auto __ = [] { ios_base::sync_with_stdio(0); cin.tie(0); cout.tie(0); return 0; }();
int main() { int N; int time; int ret; string str; stringstream ss; vector<vector<int>> G; vector<int> dfsD; vector<int> low;
function<void(int, int)> dfs = [&](int n, int parent) { int child = 0; bool flag = false;
dfsD[n] = low[n] = ++time;
for (auto& i : G[n]) { if (dfsD[i]) { if (parent != i) low[n] = min(dfsD[i], low[n]); continue; } ++child; dfs(i, n); low[n] = min(low[i], low[n]);
if (low[i] >= dfsD[n]) flag = true; }
if (flag && (child >= 2 || parent)) ++ret; };
while (cin >> N && N) { cin.ignore();
G.assign(N + 1, vector<int>()); dfsD.assign(N + 1, 0); low.assign(N + 1, 0); time = 0; ret = 0;
while (getline(cin, str) && str != "0") { ss.clear(); ss.str(str);
int a, b; ss >> a; while (ss >> b) { G[a].push_back(b); G[b].push_back(a); } }
dfs(1, 0); cout << ret << '\n'; } }
|
參考資料
UVa 315 & POJ 1144 Network
圖論(二):圖的割點(cut vertex)與連通度(connectivity)