算法87-----DAG有向无环图的拓扑排序

一、题目:课程排表

课程表上有一些课,是必须有修学分的先后顺序的,必须要求在上完某些课的情况下才能上下一门。问是否有方案修完所有的课程?如果有的话请返回其中一个符合要求的路径,否则返回[].

例子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].

例子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] .

BFS思路:每次找入度为0的节点。

1、先建立图(邻接表)、和入度表。

2、循环n次(n为节点数),每次找到度为0 的节点(循环n次,从头开始找),加入path中,然后将其出度的节点的入度-=1(循环入度表)。

先是找到入度为0的节点:1

将1加入path中,然后是2,3节点的入度减去1,因为1已经被处理掉了。

此时度为0的节点是2,3。

将2,3加入path中,…… 

伪代码:

循环n次:

循环n次:

找入度为0的节点

将度为0节点加入path中

循环入度表:

将度为0节点的出度节点的入度节点-=1

代码:

from collections import defaultdict
def BFS(n,arr):
    # n 为节点数,arr为【【u1,v1】,【u2,v2】……】,这里的u和v中,v是u的父节点。
    if not arr:
        return -1
    graph = defaultdict(list)
    indegree = defaultdict(int)
    path = []
    for u , v in arr:
        graph[v].append(u)
        indegree[u] += 1
    for i in range(n):
        zeroDegree = False
        for j in range(n):
            if indegree[j] == 0:
                zeroDegree = True
                break
        if not zeroDegree:
            return []
        indegree[j] -= 1
        path.append(j)
        for val in graph[j]:
            indegree[val] -= 1
    return path
n= 5
arr = [[1,0],[2,0],[3,1],[3,2],[4,0]]
print(BFS(n,arr))

DFS思路:递归

  1、建立图

  2、循环n次,每次是遍历一个节点是否已经visited且合法地加入path中了,如果False不合法则直接返回【】。

  3、遍历一个节点时会将其后面的所有子节点都处理掉。

如,先是1,将1进行dfs处理【path中加入1,2,4,8,5】

  然后是2,将2进行dfs处理,已经visited过了,继续循环

  然后是3,将3进行dfs处理,没有visited,unkown状态,【path=【1,2,4,8,5】中加入【3,6,7】】

  然后是4……,后面都是visited过的,都直接跳过。

 

 

 代码:

from collections import defaultdict
def findPath(n,arr):
    if n == 0:
        return []
    graph = defaultdict(list)
    for u , v in arr:
        graph[v].append(u)
    # 0为Unkown,1为visiting,2为visited
    path = []
    visited = [0] * n
    for i in range(n):
        if not DFS(graph,visited,path,i):
            return []
    return path
def DFS(graph,visited,path,i):
    ####i节点:其正在遍历,但它的子节点的子节点也是它,表示产生了有环,则return FALSE
    if visited[i] == 1: return False
    ####i节点 :已经遍历过,后面已经没有节点了,return true
    elif visited[i] == 2:return True
    ####表示正在遍历i节点
    visited[i] = 1
    for j in graph[i]:
        if not DFS(graph,visited,path,j):
            return False
    path.append(i)
    visited[i] = 2
    return True


n = 5
arr = [[1,0],[2,0],[3,1],[3,2],[4,0]]
print(findPath(n,arr))

猜你喜欢

转载自www.cnblogs.com/Lee-yl/p/10500569.html