207. Courses Schedule via Java

课程安排本质上是一道拓扑排序题。

拓扑排序即位找出有向图的顶点的线性排序,使得对于从顶点 u 到顶点{displaystyle v}的每个有向边{displaystyle uv} u 在排序中都在{displaystyle v}之前。

性质:

当且仅当一个有向图没有环(DAG)才有可能有拓扑排序。

任何DAG具有至少一个拓扑排序,并且已知这些算法用于在线性时间内构建任何DAG的拓扑排序。

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

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

卡恩算法:

  • 假设L是存放结果的列表,先找到那些入度为零的节点,把这些节点放到L中,因为这些节点没有任何的父节点。
  • 然后把与这些节点相连的边从图中去掉,同时更新所有节点的入度,再寻找图中的入度为零的节点。
  • 对于新找到的这些入度为零的节点来说,他们的父节点已经都在L中了,所以也可以放入L。
  • 重复上述操作,直到找不到入度为零的节点。
  • 如果此时L中的元素个数和节点总数相同,说明排序完成;如果L中的元素个数和节点总数不同,说明原图中存在环,无法进行拓扑排序。

L ← 包含已排序的元素的空列表
S ← 没有进入边的节点(入度为零的节点)的集合
当 S 非空时:
    将节点n从S移走
    将n加到L尾
    for each node m with an edge e from n to m do
        remove edge e from the graph
        if m has no other incoming edges then
            insert m into S
如 图有边 则:
    return error   (图至少有一个环)
否则: 
    return L   (以拓扑排序的顺序)

public boolean canFinish(int numCourses, int[][] prerequisites) {
        //Topological Order
        //record degree&edges
        //then remove each node which in-degree is 0
        //if the final number of node we've already removed is equal to numCourses, then return true 
        List<Integer>[] adj = new List[numCourses];
        for (int i = 0; i < numCourses; i++)
            adj[i] = new ArrayList<Integer>();
        int[] indegree = new int[numCourses];
        Queue<Integer> readyCourses = new LinkedList();
        int finishCount = 0;
        for (int i = 0; i < prerequisites.length; i++) {
            int curCourse = prerequisites[i][0];
            int preCourse = prerequisites[i][1];
            adj[preCourse].add(curCourse);
            indegree[curCourse]++;
        }
        for (int i = 0; i < numCourses; i++) {
            if (indegree[i] == 0)
                readyCourses.offer(i);
        }
        while (!readyCourses.isEmpty()) {
            int course = readyCourses.poll(); 
            finishCount++;
            for (int nextCourse : adj[course]) {
                indegree[nextCourse]--;
                if (indegree[nextCourse] == 0)
                    readyCourses.offer(nextCourse); 
            }
        }
        return finishCount == numCourses;
    }

时间复杂度

空间复杂度

留待以后

原文地址:https://www.cnblogs.com/zg1005/p/11882272.html