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;
}