强连通分量-kosaraju算法
2015-09-19 22:54
381 查看
kosaraju算法
大概思路:正向存储图,用vector t表示,反向存储图,用vector rt
表示,先深搜正向图,并按遍历到的顺序入栈;然后依次取栈顶元素并删除栈顶元素,以此为起点深搜反向图,每深搜一次,强连通分量个数加一。
模板
#include <iostream> #include <vector> #include <stack> #include <string.h> #include <memory.h> #include <cstdio> #include <stdio.h> using namespace std; const int N = 10005; vector<int> t ,rt ; bool visit ; stack<int> s; int n,m; void dfs(int v){ visit[v]=1; for(int i=0;i<t[v].size();i++){ if(!visit[t[v][i]]){ dfs(t[v][i]); } } s.push(v); } void r_dfs(int v){ visit[v]=1; for(int i=0;i<rt[v].size();i++){ if(!visit[rt[v][i]]){ r_dfs(rt[v][i]); } } } int kosaraju(){ //这个if语句我也不知道干嘛的,为什么要有。。 if(!s.empty()){ s.pop(); } memset(visit,0,sizeof(visit)); for(int i=1;i<=n;i++){ if(!visit[i]){ dfs(i); } } memset(visit,0,sizeof(visit)); int t=0; while(!s.empty()){ int node=s.top(); s.pop(); printf("|%d| ", node ); if(!visit[node]){ t++; r_dfs(node); } } return t; } int main(){ //freopen("in.txt","r",stdin); int x,y; cin>>n>>m; for(int i=0;i<m;i++){ cin>>x>>y; t[x].push_back(y); rt[y].push_back(x); } for(int i=0;i<n;i++){ for(int j=0;j<t[i].size();j++){ cout<<i<<" "<<j<<" "<<t[i][j]<<" "<<endl; } } cout<<"\n"; cout<<kosaraju()<<endl; return 0; } 我写的模板和百科的不太一样。但是大同小异; n代表节点个数,m代表有向边个数。(之前一直纠结为什么会出现节点5和两个强连通分量。。。看图)
输入
5 5
1 2
2 1
2 3
3 4
4 1
poj2186-Popular Cows
此题用到 kosaraju算法,以及所谓“缩点“的思想;“缩点”就是将属于同一连通分量的元素赋予同一值;sd[i]的值代表i元素所属的联通分量;如果sd[i]==sd[j],说明i,j属于同一联通分量;
参考前辈的代码写出来的
#include <iostream> #include <vector> #include <stack> #include <string.h> #include <memory.h> #include <cstdio> #include <stdio.h> using namespace std; const int N = 10005; vector<int> t ,rt ; bool visit ; stack<int> s; int n,m,num; int sd ,gs ; //若顶点i,j属于同一强连通分量,赋同一值; //gs[i]记录的是第i个强连通分量的内顶点个数 void dfs(int v){ visit[v]=1; for(int i=0;i<t[v].size();++i){ if(!visit[t[v][i]]){ dfs(t[v][i]); } } s.push(v); } void r_dfs(int v){ sd[v]=num; gs[num]++; visit[v]=1; for(int i=0;i<rt[v].size();++i){ if(!visit[rt[v][i]]){ r_dfs(rt[v][i]); } } } void kosaraju(){ if(!s.empty()){ s.pop(); } memset(visit,0,sizeof(visit)); for(int i=1;i<=n;i++){ if(!visit[i]){ dfs(i); } } num=0; memset(visit,0,sizeof(visit)); memset(gs,0,sizeof(gs)); while(!s.empty()){ int node=s.top(); s.pop(); if(!visit[node]){ num++; r_dfs(node); } } } void s_j(int n){ memset(visit,0,sizeof(visit)); for(int i=1;i<=n;i++){ for(int j=0;j<t[i].size();j++){ int temp=t[i][j]; if(sd[i]!=sd[temp]){ visit[sd[i]]=1; } } } int g,ans; g=0; for(int i=1;i<=num;i++){ if(!visit[i]){ ans=i; g++; } } if(g==1){ cout<<gs[ans]<<endl; } else { cout<<0<<endl; } } int main(){ //freopen("in.txt","r",stdin); int x,y; cin>>n>>m; for(int i=0;i<m;i++){ cin>>x>>y; t[x].push_back(y); rt[y].push_back(x); } kosaraju(); s_j(n); return 0; }
poj1236-Network of Schools
题目大意及思路均参考自补充:输入时第i行的输入a,b,0;代表存在i指向a,i指向b的有向边;
代码
#include <iostream> #include <vector> #include <stack> #include <string.h> #include <memory.h> #include <cstdio> #include <stdio.h> #include <math.h> using namespace std; const int N = 10005; vector<int> t ,rt ; int visit ; stack<int> s; int n,m,cnt,temp,numin,numout; int belong ,indu ,outdu ; void dfs(int x){ visit[x]=1; for(int i=0;i<t[x].size();i++){ if(!visit[t[x][i]]){ dfs(t[x][i]); } } s.push(x); } void r_dfs(int x){ visit[x]=1; belong[x]=cnt; for(int i=0;i<rt[x].size();i++){ if(!visit[rt[x][i]]){ r_dfs(rt[x][i]); } } } void kosaraju(){ memset(visit,0,sizeof(visit)); for(int i=1;i<=n;i++){ if(!visit[i]){ dfs(i); } } memset(visit,0,sizeof(visit)); while(!s.empty()){ temp=s.top(); s.pop(); if(!visit[temp]){ cnt++; r_dfs(temp); } } } void count_du(){ for(int i=1;i<=n;i++){ outdu[i]=0; indu[i]=0; } for(int i=1;i<=n;i++){ for(int j=0;j<t[i].size();j++){ int zhi=t[i][j]; if(belong[i]!=belong[zhi]){ outdu[belong[i]]++; indu[belong[zhi]]++; } } } for(int i=1;i<=cnt;i++){ if(!outdu[i]){ numout++; } if(!indu[i]){ numin++; } } if(cnt==1){ cout<<"1\n0\n"<<endl; } else{ cout<<numin<<"\n"<<max(numin,numout)<<endl; } } int main(){ //freopen("in.txt","r",stdin); cin>>n; m=0; cnt=0;numin=0;numout=0; for(int i=1;i<=n;i++){ int x; cin>>x; while(x!=0){ m++; t[i].push_back(x); rt[x].push_back(i); cin>>x; } } kosaraju(); count_du(); return 0; }
相关文章推荐
- 动易2006序列号破解算法公布
- Ruby实现的矩阵连乘算法
- C#插入法排序算法实例分析
- 超大数据量存储常用数据库分表分库算法总结
- C#数据结构与算法揭秘二
- C#冒泡法排序算法实例分析
- 算法练习之从String.indexOf的模拟实现开始
- C#算法之关于大牛生小牛的问题
- C#实现的算24点游戏算法实例分析
- c语言实现的带通配符匹配算法
- 浅析STL中的常用算法
- 算法之排列算法与组合算法详解
- C++实现一维向量旋转算法
- Ruby实现的合并排序算法
- C#折半插入排序算法实现方法
- 基于C++实现的各种内部排序算法汇总
- C++线性时间的排序算法分析
- C++实现汉诺塔算法经典实例
- PHP实现克鲁斯卡尔算法实例解析
- C#获取关键字附近文字算法实例