一个有向图称为半连通(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. 难道只有我一个人想吐槽npm这种包管理方式么

    实在忍不住吐槽 说实话有强迫症的我忍了很久了,实在是忍不住写篇文章来吐槽一下. 标题可能说的有点大了,我要吐槽的是:我可能只需要某一个小小的功能模块A,结果模块A依赖B-F这5个模块,然后B又依赖这1 ...

  2. CSS控制样式的三种方式优先级对比验证

    入职已经一个月了,自此后,就好久没有写过博客了,在此先跟关注我的博友们说声抱歉.今天,在公司的一个培训作业的驱动以及伟哥那句“再不写博客就开除你”的监督下,我终于重拾旧爱,再次登录博客园,继续与大家分 ...

  3. JavaScript字符转Unicode,顺便说句:GitHub的Oh no页面很亮

    遇到个输不出来的字符怎么办,因为输不出来的字符一般又是不常见大多数时候连名字也喊不出来的,所以想问百度谷歌大大也不大可能.如果是小白用户肯定会去把输入法软盘打开切换到其他键盘一个一个找.即使有搜狗输入 ...

  4. 为 WSUS 服务器定期运行清理向导

    在 WSUS 的管理界面的 Options 里面,可以找到 Server Cleanup Wizard 然后运行.后来想了一下,为什么不把它弄成定期运行呢! 找了一下,从 Windows Server ...

  5. C#对七牛云的操作

    1.配置环境 项目中引用 QiNiu.4.0.dll 在webconfig:<add key="USER_AGENT" value="qiniu csharp-sd ...

  6. SVNServer迁移

    本文主要记录SVNServer从windows系列迁移到Centos的过程,以下几篇文章已经描述的很好了,本文就不再赘述. 注意问题: 配置权限时空格问题:包括前面不能有空格,=两边有空格等. 参考链 ...

  7. Java中常用修饰符使用汇总

    修饰符汇总: 一:public protected default private 修饰类,修饰方法,修饰属性,修饰代码块.  类: 顶级类只能用public 修饰,顶级类不能使用private 和p ...

  8. PHP 函数基础

    1.简单函数     函数四要素:返回类型,函数名,参数列表,函数体 function Show(){      echo "hello";}Show();         输出了 ...

  9. 发布iOS应用程序到苹果APP STORE完整流程

    参考:http://blog.csdn.net/mad1989/article/details/8167529(xcode APP 打包以及提交apple审核详细流程(新版本更新提交审核)) http ...

  10. Struts2中Action取得表单数据的几种方法

    Struts2中Action取得表单数据的几种方法   Struts2中Action获得表单数据的几种方法struts2 Action获取表单传值 1.通过属性驱动式JSP: <form act ...