poj 1144 (Tarjan求割点数量)

题目链接:http://poj.org/problem?id=1144

描述
一个电话线公司(简称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;
}

原文地址:https://www.cnblogs.com/zjl192628928/p/10467126.html

时间: 2024-11-02 12:28:27

poj 1144 (Tarjan求割点数量)的相关文章

POJ 1144 无向图求割点

学长写的: #include<cstdio>#include<cstdlib>#include<cmath>#include<iostream>#include<algorithm>#include<cstring>#include<vector>using namespace std;#define maxn 10005int dfn[maxn];///代表最先遍历到这个点的时间int low[maxn];///这个点所

POJ1144 Network 题解 点双连通分量(求割点数量)

题目链接:http://poj.org/problem?id=1144 题目大意:给以一个无向图,求割点数量. 这道题目的输入和我们一般见到的不太一样. 它首先输入 \(N\)(\(\lt 100\))表示点的数量(\(N=0\)表示文件输入结束). 然后接下来每行输入一组数字. 如果这一组数字只包含一个 \(0\) ,说明本组测试数据输入结束: 否则,假设这些数可以拆分成 \(a_1,a_2,a_3, \cdots ,a_m\),则说明 \(a_1\) 这个点到 \(a_2,a_3, \cdo

UESTC 900 方老师炸弹 --Tarjan求割点及删点后连通分量数

Tarjan算法. 1.若u为根,且度大于1,则为割点 2.若u不为根,如果low[v]>=dfn[u],则u为割点(出现重边时可能导致等号,要判重边) 3.若low[v]>dfn[u],则边(u,v)为桥(封死在子树内),不操作. 求割点时,枚举所有与当前点u相连的点v: 1.是重边: 忽略 2.是树边: Tarjan(v),更新low[u]=min(low[u],low[v]); 子树个数cnt+1.如果low[v] >= dfn[u],说明是割点,割点数+1 3.是回边: 更新lo

tarjan求割点割边的思考

这个文章的思路是按照这里来的. 首先来看求割点.割点必须满足去掉其以后,图被分割.tarjan算法考虑了两个: 一,根节点如果有两颗及以上子树,它就是割点.这个应该说是显然的. 二,对于普通的结点a,如果它递归树的子树中,有任意节点b的low[b]<dfn[a],那么它就不是割点,反之则是割点. 我们先来证明如果low[b]<dfn[a],a一定不是割点.low[b]<dfn[a]说明有一个结点,通过非树枝边可以访问到a以前的结点,那么显然去掉a以后,b依然与a以上的递归树联通,a不是割

[POJ1144][BZOJ2730]tarjan求割点

求割点 一种显然的n^2做法: 枚举每个点,去掉该点连出的边,然后判断整个图是否联通 用tarjan求割点: 分情况讨论 如果是root的话,其为割点当且仅当下方有两棵及以上的子树 其他情况 设当前节点为u,一个儿子节点为v 存在low[v]>=dfn[u],也就是说其儿子节点v能连到的最前面的点都在u的下面 也就是当u断开的时候,u之前的点与以v为根的子树必然分成两个独立的块 那么这个时候u就是割点 Network A Telephone Line Company (TLC) is estab

poj1144 tarjan求割点

poj1144 tarjan求割点 额,算法没什么好说的,只是这道题的读入非常恶心. 还有,理解tarjan一定要用递归树,配合横边回边前边树边等来想.. #include <cctype> #include <cstdio> #include <cstring> #include <algorithm> using namespace std; const int maxn=100, maxm=5000; struct Graph{ struct Edge

poj1144 Network【tarjan求割点】

转载请注明出处,谢谢:http://www.cnblogs.com/KirisameMarisa/p/4319585.html   ---by 墨染之樱花 [题目链接]http://poj.org/problem?id=1144 [题目描述](半天才看明白...)给图求割点个数 [思路]直接套求割点的模板即可,就是要注意输入比较坑.代码见下,附注释 #include <iostream> #include <ios> #include <iomanip> #includ

UVA - 315 Network(tarjan求割点的个数)

题目链接:https://vjudge.net/contest/67418#problem/B 题意:给一个无向连通图,求出割点的数量.首先输入一个N(多实例,0结束),下面有不超过N行的数,每行的第一个数字代表后面的都和它存在边,0表示行输入的结束. 题解:简单的求割点模版,所谓割点就是去掉这一个点还有于这个点链接的边之后使得原来的图连通块增加. 由于这是模版题代码会加上注释. #include <iostream> #include <cstring> using namesp

poj1144 tarjan求割点 裸题

Network Time Limit: 1000MS   Memory Limit: 10000K Total Submissions: 11684   Accepted: 5422 Description A Telephone Line Company (TLC) is establishing a new telephone cable network. They are connecting several places numbered by integers from 1 to N