1.桥:是存在于无向图中的这样的一条边,如果去掉这一条边,那么整张无向图会分为两部分,这样的一条边称为桥

    也就是说  无向连通图中,如果删除某边后,图变成不连通,则称该边为桥

2.割点:无向连通图中,如果删除某点后,图变成不连通,则称该点为割点。

求取割点:

  1》当前节点为树根的时候,条件是“要有多余一棵子树”(如果这有一颗子树,去掉这个点也没有影响,如果有两颗子树,去掉这点,两颗子树就不连通了。

  2》当前节点U不是树根的时候,条件是“low[v]>=dfn[u]”,也就是在u之后遍历的点,能够向上翻,最多到u,如果能翻到u的上方,那就有环了,去掉u之后,图仍然连通。保证v向上最多翻到u才可以

树边,前向边,后向边,横叉边

图进行DFS会得到一棵DFS树(森林)

vis = 0,表示该顶点没没有被访问
vis = 1,表示该顶点已经被访问,但其子孙后代还没被访问完,也就没从该点返回
vis = 2,,表示该顶点已经被访问,其子孙后代也已经访问完,也已经从该顶点返回

DFS过程中,对于一条边u->v
vis[v] = 0,说明v还没被访问,v是首次被发现,u->v是一条树边
vis[v] = 1,说明v已经被访问,但其子孙后代还没有被访问完(正在访问中),而u又指向v?说明u就是v的子孙后代(v都访问过了),u->v是一条后向边,因此后向边又称返祖边
vis[v] = 3,z说明v已经被访问,其子孙后代也已经全部访问完,u->v这条边可能是一条横叉边,或者前向边

注意:树边,后向边,前向边,都有祖先,后裔的关系,但横叉边没有,u->v为横叉边,说明在这棵DFS树中,它们不是祖先后裔的关系它们可能是兄弟关系,堂兄弟关系,甚至更远的关系,如果是dfs森林的话,u和v甚至可以在不同的树上

在很多算法中,后向边都是有作用的,但是前向边和横叉边的作用往往被淡化,其实它们没有太大作用。

一直有个疑惑,这一天也就在看这个地方就是优化low数组的时候,如果自己的儿子节点没有被访问过,那么好说我们更新维护low数组是low[u] = min(low[u],low[v])————应付的情况就是子节点通过另一条路径访问到了祖先节点,但是当访问到的字节点被访问过的时候,为什么就要这么更新low数组low[u] = min(low[u],dfn[v])这个我没怎么想明白,后来看到了一个实例:

一个图(v,e)点为1,2,3,4,5,边有(1,2),(2,3),(3,1),(3,4),(4,5),(5,3)令1为树根。显然3为割点。不妨假设搜索顺序是(1,2),(2,3),(3,1),(3,4),(4,5),(5,3)搜索到(3,1)的时候,更新low[3] = dfn[1] = 1后搜索(3,4)、(4,5),(5,3),发现3已经遍历,那么如果此时采用low[u] = min(low[u], low[v])的话,会更新low[5] = low[3] = 1,回溯到4,low[4] = low[5] = 1,回溯到3,low[3] = low[4] = 1,然后比较发现low[4] < dfn[3],判断出3不是割点,算法错误。

所以也就是为了避免那个被访问过的点已经属于了一个联通分量了这样的话就会造成错误的联通分量融合的情况,这样也只是表面上明白了,还没有完全透彻,后续再捂捂

初始准备

const int maxn = 20010;
int n;
struct node{
int to,pre;
}e[maxn];
int id[maxn],cnt;
int index;
int low[maxn],dfn[maxn];
int cut_point[maxn];

链式前向星存储边 + index模拟时间戳 + low数组表示的意思是与"u节点及其子孙节点"相连的最先被访问到的点的访问序号。表示u节点最早可从那个节点访问到 + dfn数组为这个点的dfs访问次序

初始化过程

void init()
{
cnt = ;
index = ;
memset(low,,sizeof(low));
memset(dfn,,sizeof(dfn));
memset(id,-,sizeof(id));
memset(cut_point,,sizeof(cut_point));
}

加边函数

void add(int from,int to)
{
e[cnt].to = to;
e[cnt].pre = id[from];
id[from] = cnt++;
}

tarjan算法

注释也差不多啦

访问一个点的时候初始化两个数组,记录根节点的子树数目,对于没有访问过的回溯时两种方法判断是否为为割点

void tarjan(int u,int fa)
{
int son = 0;
dfn[u] = low[u] = ++index;
for(int i = id[u];~i;i = e[i].pre)
{
int v = e[i].to;
if(!dfn[v])//目标点没有被访问过
{
tarjan(v,u);//先访问
son++;//记录儿子数目 low[u] = min(low[u],low[v]);//更新回溯的值 if(dfn[u] <= low[v] && u != 1)//如果不是数根,而且子节点回不到父节点及其以上
cut_point[u] = 1;
if(u == 1 && son > 1)//对于根节点,如果有两个及其以上的子树,那么肯定是割点
cut_point[u] = 1;
}
else//目标点被访问过,有两种可能
//1.从开始点一个环过来的,很简单对于low数组的更新都一样
//2.从另一个点延伸过来的,那就代表被访问过的点的low数组已经
//被那个强连通分量更新了,所以我们采用他的访问次数进行更新
low[u] = min(low[u],dfn[v]);
}
}

好了接下来就是根据题目更新了

int get_cnt()
{
int ans = 0;
tarjan(1,1);
for(int i = 1;i <= n;i++)
{
if(cut_point[i])
ans++;
}
return ans;
}
int main()
{
while(~scanf("%d",&n),n)
{
init();
int s,t;
while(~scanf("%d",&s),s)
{
while(getchar() != '\n')
{
scanf("%d",&t);
add(s,t);
add(t,s);
}
}
printf("%d\n",get_cnt());
}
return 0;
}

tarjan算法--求解无向图的割点和桥的更多相关文章

  1. tarjan算法--求无向图的割点和桥

    一.基本概念 1.桥:是存在于无向图中的这样的一条边,如果去掉这一条边,那么整张无向图会分为两部分,这样的一条边称为桥无向连通图中,如果删除某边后,图变成不连通,则称该边为桥. 2.割点:无向连通图中 ...

  2. Tarjan算法初探(3):求割点与桥以及双连通分量

    接上一节Tarjan算法初探(2):缩点 在此首先提出几个概念: 割点集合:一个无向连通图G 若删除它的一个点集 以及点集中所有点相连的边(任意一端在点集中)后 G中有点之间不再连通则称这个点集是它的 ...

  3. [Tarjan系列] Tarjan算法求无向图的双连通分量

    这篇介绍如何用Tarjan算法求Double Connected Component,即双连通分量. 双联通分量包括点双连通分量v-DCC和边连通分量e-DCC. 若一张无向连通图不存在割点,则称它为 ...

  4. [Tarjan系列] Tarjan算法求无向图的桥和割点

    RobertTarjan真的是一个传说级的大人物. 他发明的LCT,SplayTree这些数据结构真的给我带来了诸多便利,各种动态图论题都可以用LCT解决. 而且,Tarjan并不只发明了LCT,他对 ...

  5. Tarjan无向图的割点和桥(割边)全网详解&算法笔记&通俗易懂

    更好的阅读体验&惊喜&原文链接 感谢@yxc的腿部挂件 大佬,指出本文不够严谨的地方,万分感谢! Tarjan无向图的割点和桥(割边) 导言 在掌握这个算法前,咱们有几个先决条件. [ ...

  6. 求 无向图的割点和桥,Tarjan模板

    /* 求 无向图的割点和桥 可以找出割点和桥,求删掉每个点后增加的连通块. 需要注意重边的处理,可以先用矩阵存,再转邻接表,或者进行判重 */ const int MAXN = 10010; cons ...

  7. tarjan算法求无向图的桥、边双连通分量并缩点

    // tarjan算法求无向图的桥.边双连通分量并缩点 #include<iostream> #include<cstdio> #include<cstring> ...

  8. Tarjan算法:求解图的割点与桥(割边)

    简介: 割边和割点的定义仅限于无向图中.我们可以通过定义以蛮力方式求解出无向图的所有割点和割边,但这样的求解方式效率低.Tarjan提出了一种快速求解的方式,通过一次DFS就求解出图中所有的割点和割边 ...

  9. tarjan算法与无向图的连通性(割点,桥,双连通分量,缩点)

    基本概念 给定无向连通图G = (V, E)割点:对于x∈V,从图中删去节点x以及所有与x关联的边之后,G分裂为两个或两个以上不相连的子图,则称x为割点割边(桥)若对于e∈E,从图中删去边e之后,G分 ...

随机推荐

  1. PAT 1039 到底买不买(20)(20 分)

    1039 到底买不买(20)(20 分) 小红想买些珠子做一串自己喜欢的珠串.卖珠子的摊主有很多串五颜六色的珠串,但是不肯把任何一串拆散了卖.于是小红要你帮忙判断一下,某串珠子里是否包含了全部自己想要 ...

  2. ParseCrontab类,解析时间规则

    <?php /** * Created by PhpStorm. * User: ClownFish 187231450@qq.com * Date: 14-12-27 * Time: 上午11 ...

  3. windows上安装RabbitMQ

    windows下 安装 rabbitMQ 及操作常用命令 rabbitMQ是一个在AMQP协议标准基础上完整的,可服用的企业消息系统.它遵循Mozilla Public License开源协议,采用 ...

  4. Android.HowToDefineCustomView

    Custom View Errors E1 在使用自定义CustomView时,出现以下runtime error: Android.View.InflateException: Binary XML ...

  5. 用vs2015 编译 web app ionic

    1.要下载https://git-for-windows.github.io/ 2.下载ionic模版

  6. SCM_SVN_CVS

    SCM_SVN_CVS SCM:一种用于记录并控制软件数据的工具.比如有:CVS(有过时趋势)和SVN(更加常用). 版本控制的概念: Respository:仓库 Workspace:工作台 Del ...

  7. Android Studio Tip of the Day

    1. Alt + Q 可以查看一个方法的简单参数列表. 2. 查看一个类,如果是eclipse的话,一般直接是F3, 现在的F3好痛苦.只能改为Ctrl + H,将就着用. 3. Ctrl + J 语 ...

  8. *args 和**kwargs 的溯源

    *args:arguments:表示参数,代表一个tuple**kwargs:表示关键字参数,代表一个dict 也就是keyword args.keyword就表示字典,也就是关键字.为什么叫关键字. ...

  9. ros主从关系

    主机: 在~/.bashrc里面输入 export ROS_MASTER_URI=http://localhost:11311export ROS_HOSTNAME=192.168.4.1 其ip地址 ...

  10. Oracal 学习之用户角色创建分配表空间 给角色分配权限

    //创建角色inspur 密码为inspur,默认的表空间为USERS create user inspur identified by inspur default tablespace USERS ...