Kosaraju算法

//有向图的强连通分量
/*
	强连通分量
	
	再一个强连通分量中,任何两点都可达
	
	将所有的强连通分量看作一个点
	得到的所有有向图一定是DAG(有向无环图)
	如果存在环的话,那么这个环上的节点必然能够组成强连通分量
	 
*/ 
#include<vector>
#include<iostream>
#include<stdlib.h>
#include<algorithm>
#include<fstream>
#include<set> 
#include<map>

using namespace std;

typedef struct VNode{
	int indegree, outdegree;
	VNode(){
		indegree = 0;
		outdegree = 0;
	}
	set<int> st;//map key 是节点号,即该节点到key之间有一条边,权重是value 
}VN;

typedef struct Graph{
	int v,e;
	VN* ag;
}G;

void initG(G* g, G* rg);
void DFS(G* g, int v, int flag);
void Kosaraju(G* g, G* rg);

int* visited;
int  scccount = 0;
vector<int> ve;
 
int main(){
	G* g = new G;
	G* rg = new G; 
	initG(g, rg);
	
	Kosaraju(g, rg);
	cout<<scccount;
	
	return 0;
} 

void initG(G* g, G* rg){
	ifstream infile;//输入流
	infile.open("data.txt",ios::in); 
	if(!infile.is_open()){
		cout << "Flie open failure" <<endl;
		return;
	}
 
	infile >> g->v >> g->e ;
	rg->v = g->v;
	rg->e = g->e;
	g->ag = new VN[g->v];
	rg->ag = new VN[rg->v];
	visited = new int[g->v];
	
	fill(visited, visited+g->v, 0);
	 
	//Input the edge and weight
	for(int i = 0; i < g->e; i++){
		int node1, node2;
		infile >> node1 >> node2;
		g->ag[node1].st.insert(node2);  //有向图
		rg->ag[node2].st.insert(node1);	//反图 
	}
	
	infile.close();
}
void DFS(G* g, int v, int flag){
	visited[v] = flag;	
	set<int>::iterator it = g->ag[v].st.begin();
	for(; it != g->ag[v].st.end(); it++){
		if(visited[*it] == 0){
			DFS(g,*it,flag);
		}
	}
	ve.push_back(v);
}

void Kosaraju(G* g, G* rg){
	for(int i = 0; i < g->v; i++){
		if(visited[i] == 0){
			DFS(g,i,1);

		}
	}	
	reverse(ve.begin(),ve.end());//逆序伪拓扑排序 
	fill(visited,visited+g->v, 0);

	int flag = 0;
	for(int i = 0; i < ve.size(); i++){
		if(visited[ve[i]] == 0){
			flag++;
			DFS(rg,ve[i],flag);//传入的rg,反图 
		}
	}
	scccount = flag;
} 
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值