您的位置:首页 > 其它

强连通分量-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;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  kosaraju算法 算法