一个有向图称为半连通(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算法的更多相关文章

  1. 7-6-有向图强连通分量的Kosaraju算法-图-第7章-《数据结构》课本源码-严蔚敏吴伟民版

    课本源码部分 第7章  图 - 有向图强连通分量的Kosaraju算法 ——<数据结构>-严蔚敏.吴伟民版        源码使用说明  链接☛☛☛ <数据结构-C语言版>(严 ...

  2. Kosaraju算法、Tarjan算法分析及证明--强连通分量的线性算法

    一.背景介绍 强连通分量是有向图中的一个子图,在该子图中,所有的节点都可以沿着某条路径访问其他节点.强连通性是一种非常重要的等价抽象,因为它满足 自反性:顶点V和它本身是强连通的 对称性:如果顶点V和 ...

  3. 有向图强连通分量的Tarjan算法和Kosaraju算法

    [有向图强连通分量] 在有向图G中,如果两个顶点间至少存在一条路径,称两个顶点强连通(strongly connected).如果有向图G的每两个顶点都强连通,称G是一个强连通图.非强连通图有向图的极 ...

  4. 【强连通分量】tarjan算法及kosaraju算法+例题

    阅读前请确保自己知道强连通分量是什么,本文不做赘述. Tarjan算法 一.算法简介 Tarjan算法是一种由Robert Tarjan提出的求有向图强连通分量的时间复杂度为O(n)的算法. 首先我们 ...

  5. 连通图算法详解之① :Tarjan 和 Kosaraju 算法

    相关阅读: 双连通分量 ,割点和桥 简介 在阅读下列内容之前,请务必了解 图论相关概念 中的基础部分. 强连通的定义是:有向图 G 强连通是指,G 中任意两个结点连通. 强连通分量(Strongly ...

  6. tarjan算法和Kosaraju算法

    tarjan算法和Kosaraju算法是求有向图的强连通分量的算法: #include<iostream> #include<cstring> using namespace ...

  7. (转)求有向图的强连通分量个数(kosaraju算法)

    有向图的连通分量的求解思路 kosaraju算法 逛了很多博客,感觉都很难懂,终于找到一篇能看懂的,摘要记录一下 原博客https://www.cnblogs.com/nullzx/p/6437926 ...

  8. 算法数据结构 | 三个步骤完成强连通分量分解的Kosaraju算法

    强连通分量分解的Kosaraju算法 今天是算法数据结构专题的第35篇文章,我们来聊聊图论当中的强连通分量分解的Tarjan算法. Kosaraju算法一看这个名字很奇怪就可以猜到它也是一个根据人名起 ...

  9. 算法学习笔记:Kosaraju算法

    Kosaraju算法一看这个名字很奇怪就可以猜到它也是一个根据人名起的算法,它的发明人是S. Rao Kosaraju,这是一个在图论当中非常著名的算法,可以用来拆分有向图当中的强连通分量. 背景知识 ...

随机推荐

  1. Hello Mybatis 01 第一个CRUD

    What's the Mybatis? MyBatis 本是apache的一个开源项目iBatis, 2010年这个项目由apache software foundation 迁移到了google c ...

  2. 《OOC》笔记(0)——为何要看这本书

    <OOC>笔记(0)——为何要看这本书 <OOC>全名是<Object-oriented Programming with ANSI-C>,作者Axel-Tobia ...

  3. 纠结于搞.Net待遇不高的同学入...

    最近看到不少抱怨搞.net工资低的帖子.别的方向我不是太清楚,作为搞了近8年.Net信息系统开发的码农也想发表下自己的意见. 由于我的阅历和能力有限,首先想限定下本文的范围.这里说的“信息系统”主要包 ...

  4. 基于Task的异步模式--全面介绍

    今天是国庆长假第一天,也是今天十月的开始.每到这个时候都是看海的季节-一个看"人海"的季节.反正我是不想在这样一个尴尬期出去放松自己,于是不如在家写写博客,长点本领呢.今天就来给大 ...

  5. ./在Linux下是什么意思

    在网上找的答案: . 在这里表示的是当前目录,就像 .. 表示上级目录一样. 这个 / 表示的是目录级别的分隔符,他之前的就是目录名,./aaa/ 表明的就是 . (也就是当前目录)下面的 aaa 目 ...

  6. 爱上MVC系列~过滤器实现对响应流的处理

    回到目录 MVC的过滤器相信大家都用过,一般用来作权限控制,因为它可以监视你的Action从进入到最后View的渲染,整个过程ActionFilter这个过滤器都参与了,而这给我们的开发带来了更多的好 ...

  7. git 操作简明扼要,命令不需要多,够用就行

    提升能力最快的方法就是做项目. 从前使用svn时,最开始是自己看网上教程,只会一个从服务端checkout文件,update一下,commit一下,后来使用到了分支,感觉好了不少,感觉svn还挺不错的 ...

  8. KnockoutJS 3.X API 第四章 表单绑定(6) click绑定

    目的 click绑定主要作用是用于DOM元素被点击时调用相关JS函数.最常见用于button.input.a元素. 例如: You've clicked timesClick me var viewM ...

  9. .NET面试题解析(07)-多线程编程与线程同步

      系列文章目录地址: .NET面试题解析(00)-开篇来谈谈面试 & 系列文章索引 关于线程的知识点其实是很多的,比如多线程编程.线程上下文.异步编程.线程同步构造.GUI的跨线程访问等等, ...

  10. Java多线程系列--“JUC线程池”05之 线程池原理(四)

    概要 本章介绍线程池的拒绝策略.内容包括:拒绝策略介绍拒绝策略对比和示例 转载请注明出处:http://www.cnblogs.com/skywang12345/p/3512947.html 拒绝策略 ...