判斷有向圖是否有環

如何判斷有向圖是否有環ui

  • 1.dfs,bfs
  • 2.拓撲排序

使用拓撲排序來解決這個問題,首先什麼是拓撲排序?一直刪除出度爲0的頂點直到沒有出度爲0的頂點,若是最終還有頂點存在就說明有環,而且是由剩下的頂點組成的環。code

例如 有有向圖的鄰接表以下排序

0->1
1->0
1->2
2->3

首先 3這個頂點出度爲 0那先刪除跟3有關的鄰接表,剩下的鄰接表有it

0->1
1->0
1->2

而後 2這個頂點出度爲0,刪除跟2有關的鄰接表,剩下的鄰接表有map

0->1
1->0

已經沒有出度爲0的鄰接表了,剩下的0,1組成了有向圖的環top

代碼實現集合

// 有向圖是否有環
func canFinish(numCourses int, prerequisites [][]int) bool {
   // 鄰接表map
    adj := make(map[int]map[int]struct{}, numCourses)
    // 反向鄰接表map
    adjR := make(map[int]map[int]struct{}, numCourses)
    for i := 0; i < len(prerequisites); i++ {
        _, ok := adj[prerequisites[i][1]]
        if !ok {
            adj[prerequisites[i][1]] = make(map[int]struct{}, numCourses)

        }
        _, ok = adjR[prerequisites[i][0]]
        if !ok {
            adjR[prerequisites[i][0]] = make(map[int]struct{}, numCourses)
        }
        adj[prerequisites[i][1]][prerequisites[i][0]] = struct{}{}
        adjR[prerequisites[i][0]][prerequisites[i][1]] = struct{}{}

    }
    // 全部頂點集合map
    g := make(map[int]struct{}, numCourses)
    for i := 0; i < numCourses; i++ {
        g[i] = struct{}{}
    }
    return !topology(adj, adjR, g)
}

// 圖的拓撲排序  一直刪除出度爲0的頂點直到全部頂點出度大於0或者沒有頂點了
func topology(adj, adjR map[int]map[int]struct{}, g map[int]struct{}) bool {
    var existsZero bool
    for k := range g {
        // 出度爲0 刪除這個節點
        if _, ok := adj[k]; !ok {
            existsZero = true
            delete(g, k)
            mr, ok1 := adjR[k]
            if ok1 {
                for i := range mr {
                    delete(adj[i], k)
                    if len(adj[i]) == 0 {
                        delete(adj, i)
                    }
                }

                delete(adjR, k)
            }
        }

    }

    if len(g) > 0 && existsZero {
        return topology(adj, adjR, g)
    }

    if len(g) > 0 && !existsZero {
        return true
    }

    return false
}
相關文章
相關標籤/搜索