码迷,mamicode.com
首页 > 编程语言 > 详细

Course Schedule II---拓扑排序解题思路

时间:2018-05-22 23:54:15      阅读:278      评论:0      收藏:0      [点我收藏+]

标签:++   说明   rom   visit   nta   logical   wiki   and   函数返回   

主要按照以下思路进行介绍:

1. 拓扑排序

2. Course Schedule II题目分析

3. AC代码(C++)

 

1. 拓扑排序                                                 

摘自维基百科:

图论中,由一个有向无环图(DAG, Directed Acyclic Graph)的顶点组成的序列,当且仅当满足下列条件时,称为该的一个拓扑排序英语:Topological sorting)。

  1. 每个顶点出现且只出现一次;
  2. 若A在序列中排在B的前面,则在图中不存在从B到A的路径

也可以定义为:拓扑排序是对有向无环图的顶点的一种排序,它使得如果存在一条从顶点A到顶点B的路径,那么在排序中B出现在A的后面。

也就是说:拓扑排序是DAG顶点的一种排序,非DAG图没有拓扑排序。

2. Course Schedule II题目分析                  

1. 题目:

There are a total of n courses you have to take, labeled from 0 to n-1.

Some courses may have prerequisites, for example to take course 0 you have to first take course 1, which is expressed as a pair: [0,1]

Given the total number of courses and a list of prerequisite pairs, return the ordering of courses you should take to finish all courses.

There may be multiple correct orders, you just need to return one of them. If it is impossible to finish all courses, return an empty array.

Example 1:

Input: 2, [[1,0]] 
Output: [0,1]
Explanation: There are a total of 2 courses to take. To take course 1 you should have finished   
             course 0. So the correct course order is [0,1] .

Example 2:

Input: 4, [[1,0],[2,0],[3,1],[3,2]]
Output: [0,1,2,3] or [0,2,1,3]
Explanation: There are a total of 4 courses to take. To take course 3 you should have finished both     
             courses 1 and 2. Both courses 1 and 2 should be taken after you finished course 0. 
             So one correct course order is [0,1,2,3]. Another correct ordering is [0,2,1,3] .

2. 题目分析

此题中在课程之间有约束的情况下,求可行的课程顺序。可利用拓扑排序来解:若有环,则没有拓扑排序,否则输出一个拓扑排序结果。

拓扑排序主要有两种思路:

kahn算法,也就是BFS的思路,类似于剥洋葱;

DFS算法.

2.1 BFS

数据结构:【先修课程】【课程】

主要思路:a. 先找到所有入度为0的节点放入stack或者queue中;

     b. 从stack或者queue中取出一个节点,将此节点加入拓扑排序结果队列中,删除从此节点指向其他节点的边,并将其他节点的入队-1;

     c. 若删除后,有新的入度为0的节点,则加入stack或者queue中。

     d. 循环步骤b,c,直到stack或者queue为空。

     e. 最后判断:若仍有节点的入度不为0,则说明此拓扑存在至少一个环,没有拓扑排序结果;否则,输出拓扑排序结果。

伪代码:

L← Empty list that will contain the sorted elements
S ← Set of all nodes with no incoming edges
while S is non-empty do
    remove a node n from S
    insert n into L
    foreach node m with an edge e from n to m do
        remove edge e from thegraph
        if m has no other incoming edges then
            insert m into S
if graph has edges then
    return error (graph has at least onecycle)
else 
    return L (a topologically sortedorder)

2.2 DFS

数据结构:【课程】【先修课程】

主要思路1:a.找到所有出度为0的节点,分别沿着此节点向前递归遍历,找此节点的前一个节点;

       b. 遍历完所有达到此节点的节点;

       c. 将此节点加入拓扑排序队列中;

       d. 此过程中若遍历到正在递归调用,但是还没有返回的节点,则说明此拓扑存在环。

伪代码:

L ← Empty list that will contain the sorted nodes
S ← Set of all nodes with no outgoing edges
for each node n in S do
    visit(n) 
function visit(node n)
    if n has not been visited yet then
        mark n as visited
        for each node m with an edgefrom m to ndo
            visit(m)
        add n to L

主要思路2:a. 从0开始遍历所有节点,此节点的前一个节点;

       b. 遍历完此节点到达的节点;

       c. 将此节点加入拓扑排序队列中;

       d. 此过程中若遍历到正在递归调用,但是还没有返回的节点,则说明此拓扑存在环。

       e. 需要将得到的拓扑排序序列反向。

2.3 思路比较:

摘自:https://blog.csdn.net/dm_vincent/article/details/7714519

Kahn算法不需要检测图为DAG,如果图为DAG,那么在出度为0的集合为空之后,图中还存在没有被移除的边,这就说明了图中存在环路。

而基于DFS的算法需要首先确定图为DAG,当然也能够做出适当调整,让环路的检测和拓扑排序同时进行,毕竟环路检测也能够在DFS的基础上进行。

二者的复杂度均为O(V+E)

3. 代码                                                  

3.1  BFS

 1 class Solution {
 2 public:
 3     vector<int> findOrder(int numCourses, vector<pair<int, int>>& prerequisites) 
 4     {
 5         vector<int> res;
 6         vector<int> initres;
 7         if(numCourses<=0)
 8             return initres;
 9         vector<set<int> > preToCourseTable(numCourses);
10         vector<int> inDegree(numCourses,0);
11         for(auto elem:prerequisites)
12         {
13             preToCourseTable[elem.second].insert(elem.first);
14             inDegree[elem.first]++;
15         }
16         stack<int> zeroInDegree;
17         for(int i=0;i<numCourses;i++)
18         {
19             if(0 == inDegree[i])
20                 zeroInDegree.push(i);
21         }
22         while(!zeroInDegree.empty())
23         {
24             int curr = zeroInDegree.top();
25             res.push_back(curr);
26             zeroInDegree.pop();
27             for(auto elem: preToCourseTable[curr])
28             {
29                 inDegree[elem]--;
30                 if(0 == inDegree[elem])
31                    zeroInDegree.push(elem); 
32             }
33         }
34         for(int i=0;i<numCourses;i++)
35         {
36             if(inDegree[i]>0)
37                 return initres;
38         }
39         return res;
40     }
41 };

3.2 思路1:

 1 class Solution {
 2 public:
 3     vector<int> findOrder(int numCourses, vector<pair<int, int>>& prerequisites) 
 4     {
 5         vector<int> res;
 6         vector<int> initres;
 7         if(numCourses<=0)
 8             return initres;
 9         vector<set<int> > courseToPreTable(numCourses);
10         vector<int> courseToCount(numCourses,0);
11         for(auto elem:prerequisites)
12         {
13             courseToPreTable[elem.first].insert(elem.second);
14             courseToCount[elem.second]++;
15         }
16         //-1,visiting,0,not visited,1,visited
17         vector<int> visitState(numCourses,0);
18         for(int i=0;i<numCourses;i++)
19         {
20             if(0 == visitState[i] && 0 == courseToCount[i])
21             {
22                 if(!dfs(courseToPreTable,res,visitState,i))//dfs函数返回false,说明存在环。
23                     return initres;
24             }
25         }
26         for(int i=0;i<numCourses;i++)
27         {
28             if(0 == visitState[i])
29                 return initres;
30         }
31         return res;
32     }
33     bool dfs(vector<set<int> >& courseToPreTable,vector<int>& res,vector<int>& visitState,int course)
34     {
35         if(1 == visitState[course])
36             return true;
37         visitState[course] = -1;
38         for(auto elem:courseToPreTable[course])
39         {
40             if(-1 == visitState[elem] || !dfs(courseToPreTable,res,visitState,elem))//dfs函数返回false,说明存在环。
41                     return false;
42         }
43         visitState[course] = 1;
44         res.push_back(course);
45         return true;
46     }
47 };

3.2 思路2:

 1 class Solution {
 2 public://DFS,随便找一个节点开始找,遍历所有节点,DFS在此过程中还要检查是否有环
 3     vector<int> findOrder(int numCourses, vector<pair<int, int>>& prerequisites) 
 4     {
 5         vector<int> res;
 6         vector<int> initres;
 7         //if(numCourses<=0 || 0 == prerequisites.size())
 8         //if(numCourses<=0)
 9             //return initres;
10         vector<set<int> > preToCourseTable(numCourses);
11         for(auto elem:prerequisites)
12         {
13             preToCourseTable[elem.second].insert(elem.first);
14         }
15         //-1,visiting,0,not visited,1,visited
16         vector<int> visitState(numCourses,0);
17         for(int i=0;i<numCourses;i++)
18         {
19             if(0 == visitState[i])
20             {
21                 if(!dfs(preToCourseTable,res,visitState,i))//dfs函数返回false,说明存在环。
22                     return initres;
23             }
24         }
25         vector<int> resres(res.rbegin(),res.rend());
26         return resres;
27     }
28     bool dfs(vector<set<int> >& preToCourseTable,vector<int>& res,vector<int>& visitState,int course)
29     {
30         if(1 == visitState[course])
31             return true;
32         visitState[course] = -1;
33         for(auto elem:preToCourseTable[course])
34         {
35             if(-1 == visitState[elem] || !dfs(preToCourseTable,res,visitState,elem))//dfs函数返回false,说明存在环。
36                     return false;
37         }
38         res.push_back(course);
39         visitState[course] = 1;
40         return true;
41     }
42 };

 

Course Schedule II---拓扑排序解题思路

标签:++   说明   rom   visit   nta   logical   wiki   and   函数返回   

原文地址:https://www.cnblogs.com/jingjingblog/p/9074532.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!