1. 程式人生 > >算法87-----DAG有向無環圖的拓撲排序

算法87-----DAG有向無環圖的拓撲排序

gree 方案 跳過 分享圖片 分享 return tail take !=

一、題目:課程排表---210

課程表上有一些課,是必須有修學分的先後順序的,必須要求在上完某些課的情況下才能上下一門。問是否有方案修完所有的課程?如果有的話請返回其中一個符合要求的路徑,否則返回[].

例子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))

二、題目:解題報告,連除----399

已經給出了某些變量的比值,求新的變量的比值。如果這個變量沒有出現過,或者不可到達,那麽返回-1.

技術分享圖片

DFS思路: 

題目中給了頂點和頂點之間的關系,其實就是制定了這個圖的樣子。然後要求的新的比值其實就是從一個頂點到達另外一個頂點的路徑,並且把這條路徑上所有的權重相乘。

註意,如果a/b=3,那麽從a到b是3,那麽從b到a是1/3.

既然是從一個頂點出發到達另外一個頂點,所以應該是dfs解決的問題。
原文:https://blog.csdn.net/fuxuemingzhu/article/details/82591165

  1、建立圖  {a:{b : 2.0} 、b:{a:1 /2.0,c:3.0}、c:{b:1/3.0}}

  2、不在圖中則返回-1  

  3、在圖中,x == y,返回1,x != y,返回x到y的拓撲排序的權重相乘值。

代碼:

  

from collections import defaultdict
def solveque(arr ,values , que):
    if not arr:
        return [-1] * len(que)
    if not que:
        return []
    graph = defaultdict(dict)
    for (x,y) , value in zip(arr,values):
        graph[x][y] = value
        graph[y][x] = 1/value if value else 0
    for x,y in que:
        if x in graph and y in graph:
            return dfs(graph,x,y,set())
        else:
            return -1.0
def dfs(graph,x,y,visited):
    if x == y:
        return 1.0
    visited.add(x)
    for k in graph[x]:
        if k in visited:continue
        visited.add(k)
        d = dfs(graph,k,y,visited)
        if d > 0:
            return d*graph[x][k]
    return -1.0
arr = [[a,b],[b,c]]
values = [2.0,3.0]
que = [[a,c],[a,v]]
print(solveque(arr ,values , que))

算法87-----DAG有向無環圖的拓撲排序