Johnson算法寻找图中的所有简单环路

2024-01-27 01:08

本文主要是介绍Johnson算法寻找图中的所有简单环路,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

Johnson算法论文:https://www.cs.tufts.edu/comp/150GA/homeworks/hw1/Johnson%2075.PDF

Johnson算法讲解视频:https://www.youtube.com/watch?v=johyrWospv0

一篇解释原理较好的博客:https://blog.csdn.net/Azeroit/article/details/105401120?utm_medium=distribute.pc_relevant.none-task-blog-BlogCommendFromMachineLearnPai2-2.nonecase&depth_1-utm_source=distribute.pc_relevant.none-task-blog-BlogCommendFromMachineLearnPai2-2.nonecase

C++实现代码:

#include <iostream>
#include<vector>
#include<map>
#include<cstring>
using namespace std;//using johnson algorithm
int visited[10010],dfn[10010],low[10010],ins[10010],stack[10010],color[10010],top=0,cnt,N,M,stamp=0;
vector<int> V[10010],VC[10010];
vector<int> scc[10010];map<int,vector<int>> blockedmap;  //stack,ins 可以重复利用,ins充当blockedset的作用 先用vector,不对就换set
vector<vector<int>> ans;  //存放结果
void tarjan(int u){dfn[u]=low[u]=++stamp;stack[++top]=u;ins[u]=1;for(int i=0;i<V[u].size();i++){int v=V[u][i];if(!dfn[v]){tarjan(v);low[u]=min(low[u],low[v]);}else if(ins[v])low[u]=min(low[u],dfn[v]);}if(dfn[u]==low[u]){cnt++; int y;do {y = stack[top--], ins[y] = 0;/*c[y] = cnt, */color[y] = cnt,scc[cnt].push_back(y);} while (u!= y);}
}void stronglycomponent(){for(int i=1;i<=N;i++){if(!dfn[i]) tarjan(i);}
}void unlock(int u){ins[u]=0;if(!blockedmap[u].empty()){for(auto e:blockedmap[u]){if(ins[e]) unlock(e);}}blockedmap[u].clear();
}
bool Findcycles(int start,int cur){//printf("f(%d,%d)\n",start,cur);bool f=false;// 是否找到环stack[++top]=cur;ins[cur]=1;for(auto e:VC[cur]){if(!visited[e]){if(e==start){//保存结果vector<int> path;for(int i=1;i<=top;i++)path.push_back(stack[i]);ans.push_back(path);f=true;}else if(!ins[e]){//bool flag=Findcycles(start,e);  //不能合并写f=(Findcycles(start,e))||f;  //次序不能颠倒}}}if(f) unlock(cur);else{for(auto e:VC[cur]){if(!visited[e]) blockedmap[e].push_back(cur);}}--top;return f;
}
int main()
{cin>>N>>M;//默认编号0-N-1for(int i=0;i<M;i++){int a,b;cin>>a>>b;V[a].push_back(b);}stronglycomponent();//显示强连通分量printf("显示强连通分量\n");cout<<"cnt is "<<cnt<<endl;for(int i=1;i<=cnt;i++){for(int j=0;j<scc[i].size();j++){printf("%d ",scc[i][j]);}printf("\n");}//缩点for(int i=1;i<=N;i++){for(int j=0;j<V[i].size();j++){if(color[i]==color[V[i][j]]){VC[i].push_back(V[i][j]);}}}//寻找所有简单回路memset(ins,0,sizeof(ins));for(int startindex=1;startindex<=N;startindex++){Findcycles(startindex,startindex);visited[startindex]=1;}//显示结果printf("显示结果\n");for(int i=0;i<ans.size();i++){for(int j=0;j<ans[i].size();j++){printf("%d ",ans[i][j]);}printf("\n");}
}

以视频中的输入例子为测试:

输入:

9 15
1 2
1 5
1 8
2 3
2 7
2 9
3 1
3 2
3 4
3 6
4 5
5 2
6 4
8 9
9 8

输出:

1 2 3
1 5 2 3
2 3
2 3 4 5
2 3 6 4 5
8 9

 

这篇关于Johnson算法寻找图中的所有简单环路的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/648613

相关文章

利用Python编写一个简单的聊天机器人

《利用Python编写一个简单的聊天机器人》这篇文章主要为大家详细介绍了如何利用Python编写一个简单的聊天机器人,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下... 使用 python 编写一个简单的聊天机器人可以从最基础的逻辑开始,然后逐步加入更复杂的功能。这里我们将先实现一个简单的

在MyBatis的XML映射文件中<trim>元素所有场景下的完整使用示例代码

《在MyBatis的XML映射文件中<trim>元素所有场景下的完整使用示例代码》在MyBatis的XML映射文件中,trim元素用于动态添加SQL语句的一部分,处理前缀、后缀及多余的逗号或连接符,示... 在MyBATis的XML映射文件中,<trim>元素用于动态地添加SQL语句的一部分,例如SET或W

C#实现获得某个枚举的所有名称

《C#实现获得某个枚举的所有名称》这篇文章主要为大家详细介绍了C#如何实现获得某个枚举的所有名称,文中的示例代码讲解详细,具有一定的借鉴价值,有需要的小伙伴可以参考一下... C#中获得某个枚举的所有名称using System;using System.Collections.Generic;usi

通过C#获取PDF中指定文本或所有文本的字体信息

《通过C#获取PDF中指定文本或所有文本的字体信息》在设计和出版行业中,字体的选择和使用对最终作品的质量有着重要影响,然而,有时我们可能会遇到包含未知字体的PDF文件,这使得我们无法准确地复制或修改文... 目录引言C# 获取PDF中指定文本的字体信息C# 获取PDF文档中用到的所有字体信息引言在设计和出

Python中的随机森林算法与实战

《Python中的随机森林算法与实战》本文详细介绍了随机森林算法,包括其原理、实现步骤、分类和回归案例,并讨论了其优点和缺点,通过面向对象编程实现了一个简单的随机森林模型,并应用于鸢尾花分类和波士顿房... 目录1、随机森林算法概述2、随机森林的原理3、实现步骤4、分类案例:使用随机森林预测鸢尾花品种4.1

使用IntelliJ IDEA创建简单的Java Web项目完整步骤

《使用IntelliJIDEA创建简单的JavaWeb项目完整步骤》:本文主要介绍如何使用IntelliJIDEA创建一个简单的JavaWeb项目,实现登录、注册和查看用户列表功能,使用Se... 目录前置准备项目功能实现步骤1. 创建项目2. 配置 Tomcat3. 项目文件结构4. 创建数据库和表5.

使用PyQt5编写一个简单的取色器

《使用PyQt5编写一个简单的取色器》:本文主要介绍PyQt5搭建的一个取色器,一共写了两款应用,一款使用快捷键捕获鼠标附近图像的RGB和16进制颜色编码,一款跟随鼠标刷新图像的RGB和16... 目录取色器1取色器2PyQt5搭建的一个取色器,一共写了两款应用,一款使用快捷键捕获鼠标附近图像的RGB和16

四种简单方法 轻松进入电脑主板 BIOS 或 UEFI 固件设置

《四种简单方法轻松进入电脑主板BIOS或UEFI固件设置》设置BIOS/UEFI是计算机维护和管理中的一项重要任务,它允许用户配置计算机的启动选项、硬件设置和其他关键参数,该怎么进入呢?下面... 随着计算机技术的发展,大多数主流 PC 和笔记本已经从传统 BIOS 转向了 UEFI 固件。很多时候,我们也

基于Qt开发一个简单的OFD阅读器

《基于Qt开发一个简单的OFD阅读器》这篇文章主要为大家详细介绍了如何使用Qt框架开发一个功能强大且性能优异的OFD阅读器,文中的示例代码讲解详细,有需要的小伙伴可以参考一下... 目录摘要引言一、OFD文件格式解析二、文档结构解析三、页面渲染四、用户交互五、性能优化六、示例代码七、未来发展方向八、结论摘要

MyBatis框架实现一个简单的数据查询操作

《MyBatis框架实现一个简单的数据查询操作》本文介绍了MyBatis框架下进行数据查询操作的详细步骤,括创建实体类、编写SQL标签、配置Mapper、开启驼峰命名映射以及执行SQL语句等,感兴趣的... 基于在前面几章我们已经学习了对MyBATis进行环境配置,并利用SqlSessionFactory核