无向连通图图求割点

概念:

割点:在一个无相连通图中,如果删除某个顶点后,图不再连接(即任意两点之间不再相互到达),我们称这样的顶点为割点(或者称为割顶)。

思考:

很容易想到的方法是:以此删除每个顶点,然后用深度优先搜索或者广度优先搜索来检查图是否依然连通。如果删除某个顶点后,,导致图不再联通,那么刚才删除的顶点就是割点,但是这种方法复杂度太高,所以需要换一种方法;

首相我们从图中的任意顶点开始对图进行遍历,我们在遍历的时候一定会遇到割点(废话),关键是如何确认一个顶点是割点。

假如我们深度优先遍历事访问到了k点,此时图就会被k点分成两部分。一部分是已经被访问过的点,另一部分是没有被访问过的点。如果k点事割点,那么剩下的没有被访问过点中至少会有一个点在不经过k点的情况下,是无论如何再也回不到已访问过得点了,那么一个连通图就是被k点分割成了不连通的子图;

这个算法的关键在于:当深度优先遍历访问到顶点u时,假设图中还有顶点v是没有访问过的点,如何判断顶点v在不经过顶点u的情况下是否还能回到之前访问过的任意一个点?如果从生成树的角度来说,顶点u就是顶点v的父亲,顶点v就是顶点u的儿子,而之前已经被访问过的顶点就是祖先。换句话说,如何检测顶点v在经过父节点u的情况下还能否回到祖先。我们的放大是对顶点v再进行一次深度优先遍历,但是此次遍历时不允许经过顶点u,看看还能否回到祖先。如果不能回到祖先则说明顶点u是割点。

例如以下例子:

上图是深度优先遍历访问到5号顶点的时候,图中只剩下6号顶点还没有被访问过。现在6号顶点在不经过5号顶点的情况下,可以回到之前被访问过得顶点有1,3,2和4号顶点。我们这里只需要他能够回到最早顶点的“时间戳”(即tarjan算法中的low[ ]数组)。对于6号顶点来说就是记录1,因为6号顶点能够回到的最早顶点是1号顶点,而1号顶点的时间戳为1(圆圈右上方的数)。为了不重复计算,我们用low[ ]数组来记录每个顶点在不经过父顶点时,能够回到的最小的“时间戳”:

对于某个顶点u,如果存在至少一个顶点v(即顶点u 的儿子),使得low[v]>=dfn[u],即不能回到祖先,那么u点为割点。对于本例们

号顶点的儿子只有6号顶点,且low[6]的值为1,而5号顶点的时间戳dfn[5]为5,low[6]<dfn[5],可以回到祖先,因此5号顶点不是割点。2号顶点是时间戳dfn[2]为3,他的儿子5号顶点的low[5]为3,low[5]==dfn[3],表示5号顶点不能绕过2号顶点从而访问到更早的祖先,因此2号顶点是割点;

代码实现:

#include<bits/stdc++.h>
using namespace std;
const int maxn=1000010;
int n,m;
struct link
{
    int to;
    int next;
}edge[maxn];
int head[maxn],tot;
int dfn[maxn],low[maxn];
bool flag[maxn];
int root=1;
int cnt;
inline void add(int x,int y)
{
    edge[++tot].to =y;
    edge[tot].next = head[x];
    head[x] = tot;
}
void tarjan(int u,int father)
{
    low[u] = dfn[u] = ++cnt;
    int child = 0;
    for(int i=head[u];i;i=edge[i].next)
    {
        int v=edge[i].to;
        if(!dfn[v])
        {
            child++;
            tarjan(v,u);
            low[u] = min(low[u],low[v]);
            if(u!=root&&low[v]>=dfn[u])
            {
                flag[u] =true;
            }
            if(u==root&&child==2)
            {
                flag[u] =true;
            }
        }else if(v!=father)
        {
            low[u] = min(low[u],dfn[v]);
        }
    }
}
int main()
{
    cin>>n>>m;
    for(int i=1;i<=m;i++)
    {
        int a,b;
        cin>>a>>b;
        add(a,b);
        add(b,a);
    }
    tarjan(1,root);
    for(int i=1;i<=n;i++)
    {
        if(flag[i]==true)
        {
            printf("%d ",i);
        }
    }
    return 0;
}

注:以上思路取自:《啊哈算法》

以上;

原文地址:https://www.cnblogs.com/wangqiqq/p/12337014.html

时间: 2024-07-31 20:41:36

无向连通图图求割点的相关文章

poj Transferring Sylla(如何快速的判断一个图是否是3—连通图,求割点,割边)

Transferring Sylla 首先,什么是k连通图?k连通图就是指至少去掉k个点使之不连通的图. 题目: 题目描述的很裸,就是给你一张图要求你判断这图是否是3-连通图. 算法分析: ///////////////////////////////////////////////////////////////////// (网上别人的分析,分析的很好所以直接引用了) 考虑一下不可行的情况,就是存在两点间的路径条数<3情况,那么我们可以去枚举两个点a和b,然后将其和相邻的边删除,然后判断联通

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

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

B - Network - uva 315(求割点)

题意:给一个无向连通图,求出割点的数量. 首先输入一个N(多实例,0结束),下面有不超过N行的数,每行的第一个数字代表后面的都和它存在边,0表示行输入的结束(很蛋疼的输入方式). 分析:割点的模板题 ****************************************************************** #include<stdio.h>#include<string.h>#include<stack>#include<algorith

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

hdu 4587 2013南京邀请赛B题/ / 求割点后连通分量数变形。

题意:求一个无向图的,去掉两个不同的点后最多有几个连通分量. 思路:枚举每个点,假设去掉该点,然后对图求割点后连通分量数,更新最大的即可.算法相对简单,但是注意几个细节: 1:原图可能不连通. 2:有的连通分量只有一个点,当舍去该点时候,连通分量-1: 复习求割点的好题! #include<iostream> #include<cstdio> #include<vector> using namespace std; int n,m; vector<vector&

求无向连通图的割点

求一个连通图的割点,割点的定义是,如果除去此节点和与其相关的边,图不再连通. 连通图的定义:如果图中任意两点都是连通的,那么图被称作连通图.如果此图是有向图,则称为强连通图(注意:需要双向都有路径) 割点:在无向连通图中,删除一个顶点v及其相连的边后,原图从一个连通分量变成了两个或多个连通分量,则称顶点v为割点,同时也称关节点 (Articulation Point).多连通图没有割点,若在多连通图上至少删去k个顶点才能破坏图的连通性,则称此图为k连通图.貌似有向连通图没有割点这个说法. 连通分

uva 315 Network(连通图求割点)

https://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&page=show_problem&problem=251  Network  A Telephone Line Company (TLC) is establishing a new telephone cable network. They are connecting several places numbered by integers

tarjan-无向图(求割点)

一.基本概念 1.割点:无向连通图中,如果删除某点后,图变成不连通,则称改点为割点. 2.桥:无向连通图中,如果去掉某条边后,整张无向图会分成两部分(即整张图不连通),这样的一条边成为桥. 3.点双连通分量:无割点的极大连通子图 任意两点间都有?至少两条不不经过相同边的路径 4.边双连通分量:无割边的极大连通子图 任意两点间都有?至少两条(除起点和终点外)不不经过相同点的路径 二.tarjan求割点 1)当前节点为树根时,成为割点的条件是“要有多于一个子树”(如果只有一棵子树,去掉这个点也没有影

设计一个算法,採用BFS方式输出图G中从顶点u到v的最短路径(不带权的无向连通图G採用邻接表存储)

思想:图G是不带权的无向连通图.一条边的长度计为1,因此,求带顶点u和顶点v的最短的路径即求顶点u和顶点v的边数最少的顶点序列.利用广度优先遍历算法,从u出发进行广度遍历,类似于从顶点u出发一层一层地向外扩展,当第一次找到顶点v时队列中便包括了从顶点u到顶点v近期的路径,如图所看到的,再利用队列输出最路径(逆路径),所以设计成非循环队列. 相应算法例如以下: typedef struct  { int data;//顶点编号 int parent;//前一个顶点的位置 } QUEUE;//非循环