考虑这样一个问题:给定一些计算机课程,每个课程都有前置课程,只有完成了前置课程才可以开始当前课程的学习;我们的目标是选择出一组课程,这组课程必须确保按顺序学习时,能全部被完成。每个课程的前置课程如下:
gopl.io/ch5/toposort
// prereqs记录了每个课程的前置课程
var prereqs = map[string][]string{
"algorithms": {"data structures"},
"calculus": {"linear algebra"},
"compilers": {
"data structures",
"formal languages",
"computer organization",
},
"data structures": {"discrete math"},
"databases": {"data structures"},
"discrete math": {"intro to programming"},
"formal languages": {"discrete math"},
"networks": {"operating systems"},
"operating systems": {"data structures", "computer organization"},
"programming languages": {"data structures", "computer organization"},
}
一个可行解:
1: intro to programming
2: discrete math
3: data structures
4: algorithms
5: linear algebra
6: calculus
7: formal languages
8: computer organization
9: compilers
10: databases
11: operating systems
12: networks
13: programming languages
解决的思路参考:http://www.cnblogs.com/shanyou/archive/2006/11/16/562861.html
自己写了个demo 程序如下:
#include <iostream>
#include <map>
#include <vector>
#include <string>
#include <algorithm>
#include <iterator>
using namespace std;
typedef map<string, std::vector<string> > GraphType;
GraphType g_courseGraph;
// 题目来源:http://docs.ruanjiadeng.com/gopl-zh/ch5/ch5-06.html
/*var prereqs = map[string][]string{
"algorithms": {"data structures"},
"calculus": {"linear algebra"},
"compilers": {
"data structures",
"formal languages",
"computer organization",
},
"data structures": {"discrete math"},
"databases": {"data structures"},
"discrete math": {"intro to programming"},
"formal languages": {"discrete math"},
"networks": {"operating systems"},
"operating systems": {"data structures", "computer organization"},
"programming languages": {"data structures", "computer organization"},
}
*/
void initGraph()
{
g_courseGraph["algorithms"].push_back("data structures");
g_courseGraph["calculus"].push_back("linear algebra");
g_courseGraph["compilers"].push_back("data structures");
g_courseGraph["compilers"].push_back("formal languages");
g_courseGraph["compilers"].push_back("computer organization");
g_courseGraph["data structures"].push_back("discrete math");
g_courseGraph["databases"].push_back("data structures");
g_courseGraph["discrete math"].push_back("intro to programming");
g_courseGraph["formal languages"].push_back("discrete math");
g_courseGraph["networks"].push_back("operating systems");
g_courseGraph["operating systems"].push_back("data structures");
g_courseGraph["operating systems"].push_back("computer organization");
g_courseGraph["programming languages"].push_back("data structures");
g_courseGraph["programming languages"].push_back("computer organization");
}
vector<string> getAllCourceFrom(GraphType& input)
{
std::vector<std::string> retvalVec;
for (GraphType::iterator itor = input.begin(); itor != input.end(); itor++) {
retvalVec.push_back(itor->first);
}
for (GraphType::iterator itor = input.begin(); itor != input.end(); itor++) {
std::vector<string> v = itor->second;
for(vector<string>::iterator it = v.begin(); it!=v.end(); it++){
if(find(retvalVec.begin(), retvalVec.end(),*it) == retvalVec.end()) {
retvalVec.push_back(*it);
}
}
}
return retvalVec;
}
// test getAllCourceFrom
void TestGetAllCourceFrom(){
std::vector<std::string> rst = getAllCourceFrom(g_courseGraph);
copy(rst.begin(), rst.end(), ostream_iterator<string> (cout, "\n"));
}
// 得到所有course的入度值
map<string, int> getAllDegree(GraphType& input){
map<string, int> degree;
std::vector<std::string> courseVec = getAllCourceFrom(input);
for(vector<string>::iterator it = courseVec.begin(); it!=courseVec.end(); it++){
degree[*it] = input[*it].size();
}
return degree;
}
void TestGetAllDegree(){
map<string, int> rst = getAllDegree(g_courseGraph);
for(map<string, int>::iterator it = rst.begin(); it != rst.end(); it++)
{
cout << "key=" << it->first << ", value=" << it->second << endl;
}
}
string findZero(std::vector<std::string>& courseVec, map<string, int>& inputDegree ){
for(vector<string>::iterator it = courseVec.begin(); it!=courseVec.end(); it++){
if(inputDegree[*it] == 0){ // 找到第一个 入度为 0 的就退出了
return *it;
}
}
return "";
}
void TestFindZero()
{
std::vector<std::string> courseVec = getAllCourceFrom(g_courseGraph);
map<string, int> degree = getAllDegree(g_courseGraph);
cout << findZero(courseVec, degree) <<endl;
}
void update(string course, std::vector<std::string>& courseVec, map<string, int>& inputDegree, GraphType& inputGraph)
{
if(course.empty()){ return;}
courseVec.erase(remove(courseVec.begin(),courseVec.end(), course), courseVec.end());
inputDegree[course] = -1; // 完全排除这个course
for(map<string, int>::iterator it = inputDegree.begin(); it != inputDegree.end(); it++)
{
if(inputDegree[it->first] != -1 && find(inputGraph[it->first].begin(),inputGraph[it->first].end(), course) != inputGraph[it->first].end() )
{
inputDegree[it->first]--; // 入度 -1
}
}
}
void testUpdate()
{
std::vector<std::string> courseVec = getAllCourceFrom(g_courseGraph);
map<string, int> degree = getAllDegree(g_courseGraph);
update("computer organization",courseVec, degree, g_courseGraph);
for(map<string, int>::iterator it = degree.begin(); it != degree.end(); it++)
{
cout << "before update:";
cout << "key=" << it->first << ", value=" << it->second << endl;
}
cout << "after update:";
copy(courseVec.begin(), courseVec.end(), ostream_iterator<string> (cout, "\n"));
for(map<string, int>::iterator it = degree.begin(); it != degree.end(); it++)
{
cout << "key=" << it->first << ", value=" << it->second << endl;
}
}
// 实现依赖课程图的排序
bool topo(GraphType& inputGraph, vector<string>& outputVec)
{
vector<string> courseVec = getAllCourceFrom(inputGraph); //得到所有course的vector
map<string, int> inputDegree = getAllDegree (inputGraph); // 保存所有 course 的入度情况
//sort(InputDegree) // 进行排序,排序按照字符串排序,排序的目的是可能有多个入度相同的,所以总得按照次序来逐个取
string course;
do{
course = findZero(courseVec, inputDegree); // 找到一个入度为 0的课程
if(!course.empty())
{
outputVec.push_back(course);
update(course, courseVec, inputDegree, inputGraph);
}
}while(course != ""); // 即如果还找得到入度为0 的点就继续,否则就退出了
if(outputVec.size() < courseVec.size())
{
return false; //该有向图有回路
}
else
{
return true;
}
}
int main()
{
initGraph();
vector<string> outputVec;
if(topo(g_courseGraph, outputVec)){
cout << "After topo sort:" <<endl;
copy(outputVec.begin(), outputVec.end(), ostream_iterator<string> (cout, "\n"));
}
return 0;
}