poj 1144 (Tarjan求割點數量)

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

描述
一個電話線公司(簡稱TLC)正在創建一個新的電話線纜網絡。他們鏈接了若干個地點分別從1到N編號。沒有兩個地點有相同的號碼。這些線是雙向的而且能使兩個地點保持通信。每一個地點的線都終結於電話交換機。每一個地點都有一個電話交換機。從每一個地點都能經過線纜到達其餘任意的地點,然而它並不須要直接鏈接,它能夠經過若干個交換機來到達目的地。有時候某個地點供電出問題時,交換機就會中止工做。TLC的工做人員意識到,除非這個地點是不可達的,不然這種狀況就會發生,它還會致使一些其它的地點不能互相通信。在這種狀況下咱們會稱這個地點(錯誤發生的地方)爲critical。如今工做人員想要寫一個程序找到全部critical地點的數量。幫幫他們。
輸入
輸入文件包括若組測試數據。每一組是一個網絡,每一組測試數據的第一行是地點的總數量N<100. 每一個接下來最多N行包括一個數字表示一個地點和與它相鏈接的地點的數字。這些最多N行徹底描述了整個網絡,好比,網絡中每一個直接鏈接的兩個地點被至少一行包括。一行內的全部數字都要用空格隔開。每組數據須要用單獨的一個0結束。最後的塊只有一行即N=0。
輸出
輸出除了最後一個組其餘每個組的critical地點的數量,每一個塊用一行輸出。
樣例輸入:
5
5 1 2 3 4
0
6
2 1 3
5 4 6 2
0
0
樣例輸出
1
2
提示:
你須要肯定每行的結束。爲了方便判斷,每行的結束都沒有多餘的空白
 
解題思路:求無向圖割點的數量
簡單介紹下tarjan算法求割點的原理:

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

  1. 對根節點u,若其有兩棵或兩棵以上的子樹,則該根結點u爲割點;
  2. 對非葉子節點u(非根節點),若其子樹的節點均沒有指向u的祖先節點的回邊,說明刪除u以後,根結點與u的子樹的節點再也不連通,有low[v]>=dfn[u];則節點u爲割點。
代碼:
#include<iostream>
#include<vector>
#include<cstdio>
#include<string>
#include<sstream>
using namespace std;
typedef long long ll;
const int maxn=10005;
vector<int> mp[maxn];
int n,m,ans,low[maxn],dfn[maxn],par[maxn],ap[maxn],cnt;
void init(){
    ans=0;
    cnt=0;
    for(int i=0;i<=n;i++){
        low[i]=dfn[i]=0;
        par[i]=0;
        ap[i]=0;
        mp[i].clear();
    }
}
void tarjan(int u){
    dfn[u]=low[u]=++cnt;  //cnt記錄遍歷次序
    int son=0;  //記錄子樹數量
    for(int i=0;i<mp[u].size();i++){
        int v=mp[u][i];
        if(!dfn[v]){ //v未被訪問,(u,v)爲樹邊
            son++;
            //記錄v的父親節點
            par[v]=u;
            tarjan(v);
            low[u]=min(low[u],low[v]);
            //根節點,子樹數量大於1即爲割點
            if(dfn[u]==1&&son>1&&!ap[u])
                ap[u]=1,ans++;
            //其他節點子樹可追溯到最先的祖先節點要麼爲v要麼爲u
            else if(dfn[u]!=1&&low[v]>=dfn[u]&&!ap[u])
                ap[u]=1,ans++;
        }
        else if(par[v]!=u) //節點v已被訪問,則(u,v)爲回邊
            low[u]=min(low[u],dfn[v]);
    }
}
int main(){
    int a,b;
    string s;
    while(~scanf("%d",&n)&&n){
        init();
        getchar();
        while(1){
            getline(cin,s);
            stringstream ss(s);
            ss>>a;
            if(!a)break;
            while(ss>>b&&b){
                mp[a].push_back(b);
                mp[b].push_back(a);
            }
        }
        tarjan(1);
        cout<<ans<<endl;
    }
    return 0;
}
相關文章
相關標籤/搜索