半连通分量--Tarjan/Kosaraju算法
一个有向图称为半连通(Semi-Connected),满足:对于图中任两点u,v,存在一条u到v的有向路径或者从v到u的有向路径。 若满足,则称G’是G的一个导出子图。
若G’是G的导出子图,且G’半连通,则称G’为G的半连通子图。若G’是G所有半连通子图中包含节点数最多的,则称G’是G的最大半连通子图。
判断一个图是不是半连通图
求解:<1>Kosarsju算法: [1] 新图DFS [2] 方法2
<2>Tarjan算法:[1] 新图DFS
【1】新图DFS
void init_judge(void)
{
for(int i=;i<=num_scc;i++)
{
vis_scc[i]=;
}
root=;
is_halfSCC=;
}
void judge_halfSCC(int u,int depth)
{
ENode *ptr=(ENode *)malloc(sizeof(ENode));
int son; if(depth == num_scc)
is_halfSCC = ;
else
{
ptr=rebuild_ALG->vlist[u].firstedge;
while(ptr!=NULL)
{
son=ptr->key;
if(!vis_scc[son])
{
vis_scc[son]=;
judge_halfSCC(son,depth+);
vis_scc[son]=; //回溯时要用到
}
ptr=ptr->next;
}
}
}
init_judge(); //【3】half_SCC判定 【主函数程序段】
for(int cn=;cn<=num_scc;cn++)
if(in_d[cn] == )
root = cn; //找到入度为0的点,做起点dfs
vis_scc[root]=;
judge_halfSCC(root,); if(is_halfSCC) printf("Yes\n");
else printf("No\n");
【2】方法2(仅适应于kosaraju算法)
求出缩点后所有顶点的入度ind[]。思考:如果原图G要是半连通的,那么缩点后的图mat必须要连通,这是基础的前提,不然原图都是不连通的,这时只要判断mat中顶点是否只有一个入度为0的点,如果当前的 DAG 有不止一个入度为 0 的点,那么这些点之间是不可到达的,导致图G不是半连通的。此外,mat就是一棵树,入度为0的顶点就是根,如果这个树不是一条链,那么图G也不是半连通的,不是链就说明有分叉,两个分叉之间是不能到达的,那么如何判断是否有分叉呢?答案是拓扑排序,如果排序到某个节点后,剩下的顺序不能确定,就说明出现了分叉。
其实程序是判断树的高度是否==num_scc。
void judge_half_SCC(void)
{
int i;
ENode *ptr=(ENode *)malloc(sizeof(ENode)); num_indegree_0=;
for(i=;i<=num_scc;i++)
{
if(in_degree[i]==)
num_indegree_0++;
} if(num_indegree_0 > ) //优先判断重构图是否连通
printf("No\n");
else
{
depth=; //按层处理
while()
{
num_indegree_0=;
for(i=;i<=num_scc;i++)
if(in_degree[i] == )
{
root=i;
num_indegree_0++;
}
if(num_indegree_0> || num_indegree_0==)
break; in_degree[root]=-; //标记+下层遍历
depth++;
ptr=rebuild_ALG->vlist[root].firstedge;
while(ptr!=NULL)
{
in_degree[ptr->key]--;
ptr=ptr->next;
}
}
if(depth==num_scc) //若相等
printf("Yes\n");
else printf("No\n");
}
}
求出有向图的最大半连通子图
tarjan或kosarju缩点之后变为DAG,最大节点数即为“最长链”,一条链的长度定义为所有节点的权值之和,每个scc的权值为它的节点个数。一个注意的地方就是tarjan之后重构图的时候会加入重边,要消除重边影响。一个SCC里所有点之间都是半连通的。如果两个强连通之间有边,那么这两个强连通中的任意点也是半连通的。
[1].找出入度为0的点做DFS,并统计count权值
[2].count是把父亲节点的num向孩子节点加;
[3].找出count数组中的最大值max_count即可;
[4].计算出与max_count相等的个数,即max_halfSCC个数
在程序中,首先要记录下每个SCC包含的顶点个数num[i]。
/*深度优先搜索寻找最大权值*/
void init_find(void)
{
for(int i=;i<=num_scc;i++)
{
vis_scc[i]=;
count[i]=num[i];
}
root=;
}
void Find_max_halfSCC(int u)
{
ENode *ptr=(ENode *)malloc(sizeof(ENode));
int son; ptr=rebuild_ALG->vlist[u].firstedge;
while(ptr!=NULL)
{
son=ptr->key;
if(!vis_scc[son])
{
vis_scc[son]=;
count[son]+=count[u];
Find_max_halfSCC(son);
vis_scc[son]=; //回溯时要用到
}
ptr=ptr->next;
}
}
init_find();
for(int cnt=;cnt<=num_scc;cnt++) //【3.判定】
if(in_degree[cnt] == )
{
root=cnt; //找到入度为0的点,做起点DFS vis_scc[root]=; //也可以拿到if外面,这样只是为了考虑in_d=0个数不止一个的情况
count[root]=num[root];
Find_max_halfSCC(root);
}
// 然后再执行第[][]步即可。至于求解最大半连通子图中的顶点,只要对新图的逆表作dfs即可。
void DFS_reverse_rebuild_ALG(int u)
{
int son;
ENode *ptr=(ENode *)malloc(sizeof(ENode)); vis_scc[u]=; //标记+访问+遍历
for(int v=;v<ALG->n;v++)
if(u == belong[v])
printf("%c ",ALG->vlist[v].vertex); //输出当前强连通分量u中的顶点
ptr=reverse_rebuild_ALG->vlist[u].firstedge;
while(ptr!=NULL)
{
son=ptr->key;
if(!vis_scc[son])
{
vis_scc[son]=;
DFS_reverse_rebuild_ALG(son);
vis_scc[son]=;
}
ptr=ptr->next;
}
}
memset(vis_scc,,sizeof(vis_scc));
for(int ii=;ii<=num_scc;ii++) //对新图的逆表做一次dfs
{
if(count[ii] == max_count && !vis_scc[ii])
{
vis_scc[ii]=;
DFS_reverse_rebuild_ALG(ii);
vis_scc[ii]=; //回溯时用
}
printf("\n");
}
半连通分量--Tarjan/Kosaraju算法的更多相关文章
- 7-6-有向图强连通分量的Kosaraju算法-图-第7章-《数据结构》课本源码-严蔚敏吴伟民版
课本源码部分 第7章 图 - 有向图强连通分量的Kosaraju算法 ——<数据结构>-严蔚敏.吴伟民版 源码使用说明 链接☛☛☛ <数据结构-C语言版>(严 ...
- Kosaraju算法、Tarjan算法分析及证明--强连通分量的线性算法
一.背景介绍 强连通分量是有向图中的一个子图,在该子图中,所有的节点都可以沿着某条路径访问其他节点.强连通性是一种非常重要的等价抽象,因为它满足 自反性:顶点V和它本身是强连通的 对称性:如果顶点V和 ...
- 有向图强连通分量的Tarjan算法和Kosaraju算法
[有向图强连通分量] 在有向图G中,如果两个顶点间至少存在一条路径,称两个顶点强连通(strongly connected).如果有向图G的每两个顶点都强连通,称G是一个强连通图.非强连通图有向图的极 ...
- 【强连通分量】tarjan算法及kosaraju算法+例题
阅读前请确保自己知道强连通分量是什么,本文不做赘述. Tarjan算法 一.算法简介 Tarjan算法是一种由Robert Tarjan提出的求有向图强连通分量的时间复杂度为O(n)的算法. 首先我们 ...
- 连通图算法详解之① :Tarjan 和 Kosaraju 算法
相关阅读: 双连通分量 ,割点和桥 简介 在阅读下列内容之前,请务必了解 图论相关概念 中的基础部分. 强连通的定义是:有向图 G 强连通是指,G 中任意两个结点连通. 强连通分量(Strongly ...
- tarjan算法和Kosaraju算法
tarjan算法和Kosaraju算法是求有向图的强连通分量的算法: #include<iostream> #include<cstring> using namespace ...
- (转)求有向图的强连通分量个数(kosaraju算法)
有向图的连通分量的求解思路 kosaraju算法 逛了很多博客,感觉都很难懂,终于找到一篇能看懂的,摘要记录一下 原博客https://www.cnblogs.com/nullzx/p/6437926 ...
- 算法数据结构 | 三个步骤完成强连通分量分解的Kosaraju算法
强连通分量分解的Kosaraju算法 今天是算法数据结构专题的第35篇文章,我们来聊聊图论当中的强连通分量分解的Tarjan算法. Kosaraju算法一看这个名字很奇怪就可以猜到它也是一个根据人名起 ...
- 算法学习笔记:Kosaraju算法
Kosaraju算法一看这个名字很奇怪就可以猜到它也是一个根据人名起的算法,它的发明人是S. Rao Kosaraju,这是一个在图论当中非常著名的算法,可以用来拆分有向图当中的强连通分量. 背景知识 ...
随机推荐
- [php入门] 5、初学CSS从中记下的一些基础点(For小白)
CSS是层叠式样式表,主要用来控制页面的样式. 一.CSS概述 应用CSS: 1.外部样式表,CSS写在一个单独的.CSS文件中,在head里加<link rel="styleshee ...
- Qt5.3编译错误——call of overloaded ‘max(int int)’is ambiguous
错误描述: 今天在使用Qt写一个C++函数模板的测试程序的时候,编译的时候,编译的时候出现如下错误: 错误描述为:在main函数中,进行函数max()重载时,出现(ambiguous)含糊的,不明确的 ...
- springmvc下js控制表单提交(表单提交前检验,提交后获取json返回值)
这个问题我搞了四天,终于搞懂.因为对js很不熟悉.郁闷的是后台代码出错总可以设置断点调试,前端js代码出错只能通过浏览器提供一些运行数据来分析,很不习惯. 首先说下逻辑:这是一个注册功能,我希望,注册 ...
- java source not found
今天的挑战是,为什么与源码明明放在本机,调试的时候却说source not found呢? 这个是因为,我重新建立了debug,然后没有选择对应的项目. 另外一个问题是,如果给底层的jar附上源码呢?
- loglikelihood ratio 相似度
摘要: 在机器学习中常用到各种距离或者相似度,今天在看美团推荐系统重排序的文章时看到了loglikelihood ratio 相似度,特总结起来.以后有时间再把常用的相似度或者距离梳理到一篇文章. 背 ...
- Redis学习笔记~StackExchange.Redis实现分布式Session
回到目录 对于多WEB的环境现在已经是必须的了,很难想像一台WEB服务器面对百万并发的响应,所以,我们需要多台WEB服务器集群合作,来缓解这种高并发,高吞吐的场景,而对于多WEB的场景又会有个问题出现 ...
- EF架构~linq to entity的随机排序问题
回到目录 对于从linq to sql迁移过来的开发者,对随机排序不会感到陌生,直接为datacontext添加一个方法再配合反射就可以实现随机排序了,代码如下: /// <summary> ...
- Ajax技术
1.ajax技术的背景 不可否认,ajax技术的流行得益于google的大力推广,正是由于google earth.google suggest以及gmail等对ajax技术的广泛应用,催生了ajax ...
- 第五节:表单标签的用法——value绑定和修饰符
1.表单标签的用法--value绑定和修饰符 value绑定的写法:v-bind:value 或者简写 :value 修饰符: lazy , Number , trim . 用法如: v-model ...
- 利用奇异值分解(SVD)简化数据
特征值与特征向量 下面这部分内容摘自:强大的矩阵奇异值分解(SVD)及其应用 特征值分解和奇异值分解在机器学习领域都是属于满地可见的方法.两者有着很紧密的关系,在接下来会谈到,特征值分解和奇异值分解的 ...