使用Tarjan算法求解图的割点和桥。

1、割点

主要的算法结构就是DFS,一个点是割点,当且仅当以下两种情况:
        (1)该节点是根节点,且有两棵以上的子树;
        (2)该节点的任一子节点,没有到该节点祖先的反向边(就是说如果没有这个割点,那么这个子节点和那个祖先之间不连通);

 void cutpoint_Tarjan(int u,int parent)
{
int son; //节点m的儿子节点
ENode *ptr=(ENode *)malloc(sizeof(ENode)); dfn[u]=low[u]=depth++; //访问+标记+遍历
vis[u]=;
ptr=ALG->vlist[u].firstedge;
while(ptr!=NULL)
{
son=ptr->key;
if(!vis[son])
{
DFS(son,u);
low[u]=MIN(low[u],low[son]); if(u==root) //不同之处//根节点[要定义初始访问节点,因为要考虑割点的2个判断条件]
cut[u]++;
else if(u!=root && dfn[u] <= low[son])
cut[u]++; //m是割点
}
else if(son != parent) //有后向边
{
low[u]=MIN(low[u],dfn[son]);
}
ptr=ptr->next;
}
}

2、桥

Tarjan算法求割边(桥):
【1】使用(son!=parent && dfn[son]<dfn[u]);

 void init_Tarjan(void)
{
depth=;
for(int i=;i<ALG->n;i++)
{
dfn[i]=low[i]=-;
vis[i]=;
} num_bridge=;
for(int j=;j<ALG->e;j++)
{
bridge_Node[j].front=;
bridge_Node[j].rear =;
}
} void Add_to_BNode(int front,int rear) //从坐标1开始存储
{
bridge_Node[num_bridge].front=front;
bridge_Node[num_bridge].rear =rear;
} void bridgenode_Tarjan(int u,int parent)
{
int son;
ENode *ptr=(ENode*)malloc(sizeof(ENode)); dfn[u]=low[u]=depth++; //访问+标记+遍历
vis[u]=;
ptr=ALG->vlist[u].firstedge;
while(ptr!=NULL)
{
son=ptr->key;
if(son!=parent && dfn[son]<dfn[u]) //避免走重边,效果和id一样
{
if(!vis[son])
{
bridge_node_Tarjan(son,u);
low[u]=MIN(low[u],low[son]);
if(low[son] > dfn[u]) //(u,son)是桥
{
num_bridge++;
Add_to_BNode(u,son); //存储桥
}
}
else if(son != parent)
{
low[u]=MIN(low[u],dfn[son]);
}
}
ptr=ptr->next;
}
}

【2】为每一条边标号 id记录每条边(一条无向边拆成的两条有向边id相同),每个点的父亲到它的边的标号;

 //结点定义  /*****注意边表节点定义有所变化****/
typedef struct edge_node{
int key; //儿子节点[边的终点]
int id; //边的编号
struct edge_node *next;
}ENode;
void init_Tarjan(void) //Tarjan算法初始化
{
depth=;
for(int i=;i<ALG->n;i++)
{
vis[i]=;
dfn[i]=low[i]=-;
}
count_bridge=;
for(int j=;j<=ALG->e;j++) //取值于1-e
bridge[j]=;
}
void bridge_Tarjan(int u,int id) //id是u的父亲边的编号
{
int son; //u的儿子节点
ENode *ptr=(ENode *)malloc(sizeof(ENode)); dfn[u]=low[u]=depth++; //访问+标记+遍历
vis[u]=;
ptr=ALG->vlist[u].firstedge;
while(ptr!=NULL)
{
if(ptr->id != id) //避免走重边,相当于cutpoint_Tarjan中的(son != parent)
{
son=ptr->key;
if(!vis[son])
{
bridge_Tarjan(son,ptr->id);
low[u]=MIN(low[u],low[son]);
if(dfn[u] < low[son]) //注意不取等号,当DFN[u]==LOW[v]时,当u->v dfs递归,存在一条v->u的回边,使得LOW[v]=DFN[u];故不为桥
{
bridge[ptr->id]=; //第id边是桥
printf("(%c,%c) ",ALG->vlist[u].vertex,ALG->vlist[son].vertex); //用于输出割边
}
}
else
{
low[u]=MIN(low[u],dfn[son]);
}
}
ptr=ptr->next;
}
}

割点和桥---Tarjan算法的更多相关文章

  1. 无向图的割点和桥 tarjan 模板

    #include <bits/stdc++.h> using namespace std; const int MAXN = 20005; const int MAXM = 100005; ...

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

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

  3. Tarjan算法应用 (割点/桥/缩点/强连通分量/双连通分量/LCA(最近公共祖先)问题)(转载)

    Tarjan算法应用 (割点/桥/缩点/强连通分量/双连通分量/LCA(最近公共祖先)问题)(转载) 转载自:http://hi.baidu.com/lydrainbowcat/blog/item/2 ...

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

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

  5. tarjan算法(强连通分量 + 强连通分量缩点 + 桥(割边) + 割点 + LCA)

    这篇文章是从网络上总结各方经验 以及 自己找的一些例题的算法模板,主要是用于自己的日后的模板总结以后防失忆常看看的, 写的也是自己能看懂即可. tarjan算法的功能很强大, 可以用来求解强连通分量, ...

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

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

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

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

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

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

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

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

随机推荐

  1. [专业名词·硬件] 2、DC\DC、LDO电源稳压基本常识(包含基本原理、高效率模块设计、常见问题、基于nRF51822电源管理模块分析等)·长文

    综述先看这里 第一节的1.1简单介绍了DC/DC是什么: 第二节是关于DC/DC的常见的疑问答疑,非常实用: 第三节是针对nRF51822这款芯片电源管理部分的DC/DC.LDO.1.8的详细分析,对 ...

  2. 翻译-DevOps究竟是什么?

    原文地址:http://www.drdobbs.com/architecture-and-design/what-exactly-is-devops/240009147 作者:Neil Garnich ...

  3. MVVM架构~knockoutjs系列之验证信息自定义输出~续

    返回目录 上一讲中,我以一个实际中的例子说明了knockoutjs的自定义验证功能,在使用过程中,出现了一个问题,当然了不是问题,只是一种需求,上一讲中自定义验证的表现是:当页面加载后,自动显示有问题 ...

  4. linux配置hosts

    linux配置hosts linux下配置hosts和windows下其实就是一样的,找到文件在哪里就好 sudo vim /etc/hosts

  5. Liferay7 BPM门户开发之46: 集成Activiti用户、用户组、成员关系同步

    在实际的BPM集成开发过程中,Liferay和Activiti这两个异构的系统之间,用户.组的同步需求非常重要,用来实现签收组的概念,比如指定签收组.会签.抢签都需要用到. Activiti可以通过自 ...

  6. LigerUI Tree

    <!DOCTYPE html> <%@ page language="java" contentType="text/html; charset=utf ...

  7. KendoUI系列:TreeView

    1.加载本地数据 <link href="@Url.Content("~/Content/kendo/2014.1.318/kendo.common.min.css" ...

  8. 如果正确读取SQL Server中的扩展事件?

        SQL Server中使用扩展事件捕捉所需的信息后,可以选择存放的位置.比如说内存或文件中,但无论存在哪里,其本质都是一个大XML.因此在SQL Server中读取该XML就是解析扩展事件结果 ...

  9. 兼容90%标准C的词法分析器

    不能分词八进制和数字类型加前/后缀的情况 拿这个词法分析器跑了一遍整个Nginx源码,基本都能正确的分出结果,后面有测试例子~ #ifndef _STATES_H_ #define _STATES_H ...

  10. 移动web开发之移动端真机测试

    × 目录 [1]特性 [2]安装 [3]设置[4]移动端 前面的话 chrome的开发者工具可以很好地做好模拟工作,但毕竟模拟和实际还是有差别的.所以,真机测试是一定要做的,如何高效地进行真机测试呢. ...