POJ1144 Network 題解 點雙連通份量(求割點數量)

題目連接:http://poj.org/problem?id=1144html

題目大意:給以一個無向圖,求割點數量。ios

這道題目的輸入和咱們通常見到的不太同樣。
它首先輸入 \(N\)\(\lt 100\))表示點的數量(\(N=0\)表示文件輸入結束)。
而後接下來每行輸入一組數字。測試

  • 若是這一組數字只包含一個 \(0\) ,說明本組測試數據輸入結束;
  • 不然,假設這些數能夠拆分紅 \(a_1,a_2,a_3, \cdots ,a_m\),則說明 \(a_1\) 這個點到 \(a_2,a_3, \cdots , a_m\) 之間都存在着一條邊。

因此這道題目想要表達的意思仍是同樣的 \(\Rightarrow\) 求割點的數量,只不過輸入方式和咱們平時見到的不太同樣。spa

觀察DFS搜索樹,咱們能夠發現有兩類節點能夠成爲割點:code

  • 對根節點 \(u\) ,若其有兩棵或兩棵以上的子樹,則該根結點 \(u\) 爲割點;
  • 對非葉子節點 \(u\) (非根節點),若其子樹的節點均沒有指向 \(u\) 的祖先節點的回邊,說明刪除 \(u\) 以後,根結點與 \(u\) 的子樹的節點再也不連通,有 \(low[v] \ge dfn[u]\) ;則節點 \(u\) 爲割點。

實現代碼以下:htm

#include <iostream>
#include <string>
#include <sstream>
#include <vector>
#include <cstdio>
using namespace std;
const int maxn = 10010;
int n, m, dfn[maxn], low[maxn], f[maxn], cnt, ans;
bool vis[maxn];
vector<int> g[maxn];
void init() {
    ans = cnt = 0;
    for (int i = 1; i <= n; i ++) {
        low[i] = dfn[i] = f[i] = vis[i] = 0;
        g[i].clear();
    }
}
void tarjan(int u) {
    low[u] = dfn[u] = ++cnt;
    int son_num = 0;    // 記錄子樹數量
    int sz = g[u].size();
    for (int i = 0; i < sz; i ++) {
        int v = g[u][i];
        if (!dfn[v]) {  // v未被訪問,(u,v)爲樹邊
            son_num ++;
            f[v] = u;
            tarjan(v);
            low[u] = min(low[u], low[v]);
            if (dfn[u] == 1 && son_num > 1 && !vis[u]) {    // 根節點,子樹數量大於1即爲割點
                vis[u] = true;
                ans ++;
            }
            else if (dfn[u] != 1 && low[v] >= dfn[u] && !vis[u]) {  // 其他節點子樹可追溯到最先的祖先節點要麼爲v要麼爲u
                vis[u] = true;
                ans ++;
            }
        }
        else if (f[v] != u) {   // 節點v已被訪問,則(u,v)爲回邊
            low[u] = min(low[u], dfn[v]);
        }
    }
}
int main() {
    while (~scanf("%d", &n) && n) {
        init();
        getchar();
        string s;
        int a, b;
        while (getline(cin, s)) {
            stringstream ss(s);
            ss >> a;
            if (!a) break;
            while ((ss >> b) && b) {
                g[a].push_back(b);
                g[b].push_back(a);
            }
        }
        tarjan(1);
        cout << ans << endl;
    }
    return 0;
}

參考連接:blog

相關文章
相關標籤/搜索