一个有向图称为半连通(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. [ACM_动态规划] Alignment (将军排队)

    http://acm.hust.edu.cn/vjudge/contest/view.action?cid=28415#problem/F 题目大意:有n个士兵排成一列,将军想从中抽出最少人数使队伍中 ...

  2. 在github上写个人简历——最简单却又不容易的内容罗列

    前篇博客分享了一下自己初入github的过程,傻瓜式一步步搭建好主页后,终于该做正事儿了——写简历.在脑袋中构思了很多版本,最后终于决定,先写一个最传统的版本,于是我在箱子中翻出我word版本的简历, ...

  3. ThinkPHP框架里隐藏index.php

    本文所写的配置在ThinkPHP3.2.2上测试过.按理也兼容其它版本. 首先修改配置文件: 'URL_CASE_INSENSITIVE' => true, // 默认false 表示URL区分 ...

  4. fir.im Weekly - 从 iOS 10 SDK 新特性说起

    从 iOS 7 翻天覆地的全新设计,iOS 8 中 Size Classes 的出现,应用扩展,以及 Cloud Kit 的加入,iOS 9 的分屏多任务特性,今年的 WWDC iOS 10 SDK ...

  5. JavaScript函数后面加不加括号的区别

    <!DOCTYPE html> <html> <head lang="en"> <meta charset="UTF-8&quo ...

  6. hadoop本地库与系统版本不一致引起的错误解决方法

    hadoop本地库与系统版本不一致引起的错误解决方法 部署hadoop的集群环境为 操作系统 centos 5.8 hadoop版本为cloudera   hadoop-0.20.2-cdh3u3 集 ...

  7. 每天一个linux命令(16):which命令

    我们经常在linux要查找某个文件,但不知道放在哪里了,可以使用下面的一些命令来搜索:        which  查看可执行文件的位置.       whereis 查看文件的位置.         ...

  8. Linux下MakeFile初探

    make是linux下的编译命令,用于编译和生成Linux下的可执行文件.这个命令处理的对象是Makefile,makefile等.由于make的强大解析能力,makefile文件的编写也变得极为简单 ...

  9. KnockoutJS 3.X API 第四章(13) template绑定

    目的 template绑定(模板绑定)使用渲染模板的结果填充关联的DOM元素. 模板是一种简单方便的方式来构建复杂的UI结构 . 下面介绍两种使用模板绑定的方法: 本地模板是支持foreach,if, ...

  10. SQL Server 2014云特性:无缝集成公有云

    本篇是我在IT168的约稿,原文地址:http://tech.it168.com/a2014/0620/1637/000001637358_all.shtml       IT行业已经进入了云时代,未 ...