本文主要是介绍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算法寻找图中的所有简单环路的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!