Stanford 算法入门 Week 4 Graph,BFS,DFS, partial_sort

用DFS进行拓扑排序

求强连通分量:kosaraju's algorithm 这篇例文比较好 http://scienceblogs.com/goodmath/2007/10/30/computing-strongly-connected-c/

Key Lemma:

-----------------------------------------------------------

   Programming Question-4

Question 1

Download the text file here. Zipped version here. (Right click and save link as)

The file contains the edges of a directed graph. Vertices are labeled as positive integers from 1 to 875714. Every row indicates an edge, the vertex label in first column is the tail and the vertex label in second column is the head (recall the graph is directed, and the edges are directed from the first column vertex to the second column vertex). So for example, the11th row looks liks : "2 47646". This just means that the vertex with label 2 has an outgoing edge to the vertex with label 47646

Your task is to code up the algorithm from the video lectures for computing strongly connected components (SCCs), and to run this algorithm on the given graph.

Output Format: You should output the sizes of the 5 largest SCCs in the given graph, in decreasing order of sizes, separated by commas (avoid any spaces). So if your algorithm computes the sizes of the five largest SCCs to be 500, 400, 300, 200 and 100, then your answer should be "500,400,300,200,100". If your algorithm finds less than 5 SCCs, then write 0 for the remaining terms. Thus, if your algorithm computes only 3 SCCs whose sizes are 400, 300, and 100, then your answer should be "400,300,100,0,0".

WARNING: This is the most challenging programming assignment of the course. Because of the size of the graph you may have to manage memory carefully. The best way to do this depends on your programming language and environment, and we strongly suggest that you exchange tips for doing this on the discussion forums.

-------------------------------------------------------
这个求SCC的思路参考上面kosaraju

我的代码,编译成功,第一次运行时在DFS的时候栈溢出。据前辈的修改意见有两种方法:
1.在VS里把栈的默认大小调大  http://www.1point3acres.com/bbs/thread-30666-3-1.html (我用的这个)
2.使用iterative DFS   http://en.wikipedia.org/wiki/Iterative_deepening_depth-first_search 

注意找出结果里的前5个大SCC,我刚开始用的QuickSort,结果运行一个小时没出结果(复杂度是n * log n);后来思考下只用遍历一遍,找出前5大的数就可以不用排序,就自己写了个TopFive的函数找出前5大数目记录在一个数组里,速度提高了很多,只几分钟就出了正确答案。
网上有人用了partial_sort来解决这个问题。目前还没理解好怎么用partial_sort,貌似很高深的样子

#include <stdio.h>
#include <tchar.h>
#include <vector>
#include <fstream>
#include <string>
#include <stack>
#include <iostream>

using namespace std;
#define MAX 875714

struct node {
	int n;
	bool visited;
	vector<int> toNode;
	vector<int> fromNode;
	int SCC;
};

node Graph[MAX + 1];
stack<int> order;
int SCC_num = 0;
vector<int> SCC;
int top[6] = { 0 };

void init_graph() {
	for(int i = 0; i < MAX + 1; i++) {
		Graph[i].n = i;
		Graph[i].visited = false;
	}
}

void read_data(char * path) {
	int from, to;
	FILE * fp;
	fp = fopen(path, "r");

	if(fp == NULL) {
		cout<<"FILE OPEN FAILED!"<<endl;
		return;
	} else {
	  // Set pointer to beginning of file:
  	    fseek( fp, 0L, SEEK_SET );
	}
	while( fscanf(fp,"%d %d", &from, &to) > 0) {
		Graph[from].toNode.push_back(to);
		Graph[to].fromNode.push_back(from);
	}
}

void DFS_Graph(int i) {
	if(Graph[i].visited == true) return;

	Graph[i].visited = true;
	for(int k = 0; k < Graph[i].toNode.size(); k++) {
		DFS_Graph(Graph[i].toNode[k]);
	}

	order.push(i);
	return;
}

void rDFS_Graph(int i) {
	if(Graph[i].visited == false) return;

	Graph[i].visited = false;
	int index = 0;
	for(int k = 0; k < Graph[i].fromNode.size(); k++) {
		index = Graph[i].fromNode[k];
		rDFS_Graph(index);
	}
	Graph[i].SCC = SCC_num;
	SCC[SCC_num - 1]++;
	return;
}

void TopFive() {
	for(int i = 0; i < SCC.size(); i++) {
		top[5] = SCC[i];
		for(int j = 4; j >= 0; j--) {
			if(top[j+1] > top[j]) {
				int temp = top[j];
				top[j] = top[j + 1];
				top[j + 1] = temp;
			} else break; 
		}
	}
}

int main() {
	init_graph();
	read_data("SCC.txt");

	//遍历DFS
	for(int j = 1; j < MAX + 1; j++) {
		if( !Graph[j].visited ) DFS_Graph(j);
	}
	
	//reverse DFS
	while(!order.empty()) {
		int index = order.top();
		order.pop();
		if(Graph[index].visited == true) {
			SCC_num++;
			SCC.push_back(0);
			rDFS_Graph(index);
		}
	}

	//找出SCC中前5大的元素
	TopFive();

	ofstream fout("out.txt");
	for(int i = 0; i < 5; i++) {
		fout<<top[i]<<endl;
		cout<<top[i]<<endl;
	}
	fout.close();
	
	return 0;
}




  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值