1. 程式人生 > >leetcode--785. Is Graph Bipartite?

leetcode--785. Is Graph Bipartite?

問題

Given an undirected graph, return true if and only if it is bipartite.

Recall that a graph is bipartite if we can split it’s set of nodes into two independent subsets A and B such that every edge in the graph has one node in A and another node in B.

The graph is given in the following form: graph[i] is a list of indexes j for which the edge between nodes i and j exists. Each node is an integer between 0 and graph.length - 1. There are no self edges or parallel edges: graph[i] does not contain i, and it doesn’t contain any element twice. Example 1:

Input: [[1,3], [0,2], [1,3], [0,2]]
Output: true
Explanation: 
The graph looks like this:
0----1
|    |
|    |
3----2
We can divide the vertices into two groups: {0, 2} and {1, 3}.

Example 2:

Input: [[1,2,3], [0,2], [0,1,3], [0,2]]
Output: false
Explanation: 
The graph looks like this:
0----1
| \  |
|  \ |
3----2 We cannot find a way to divide the set of nodes into two independent subsets.

Note:

  1. graph will have length in range [1, 100].
  2. graph[i] will contain integers in range [0, graph.length - 1].
  3. graph[i] will not contain i or duplicate values.
  4. The graph is undirected: if any element j is in graph[i], then i will be in graph[j].

思路與解法

題意比較簡單:即判斷輸入的圖是否可以劃分為二部圖。首先了解一下什麼是二部圖: 二部圖也稱作二分圖,假設G=(V,E)是一個無向圖,如果定點V可分割為兩個互不相交的子集(A,B),並且圖中的每條邊(i,j)所關聯的兩個定點ij分別屬於這兩個不同的頂點集(i in A, j in B),則稱圖G為一個二分圖。 圖示如下: 在這裡插入圖片描述 上圖中所有點分為兩個集合,且每個集合中的節點之間並沒有邊相連。所以是一個二部圖。 思路與想法如下: 對於一棵樹,若可以劃分為二部圖,則該樹的奇數深度層的節點必定位於同一集合A,同樣的,所有偶數深度層的節點位於另一集合B,並且,每個集合中必定不存在有邊相連的兩個點。如下圖所示:該樹可劃分為{A,D,E,F}{B,C,G,H,I,J}兩個集合。 在這裡插入圖片描述 所以,對於圖,我們也可以採用樹的思想,至於如何進行集合的劃分,我們可以對節點進行染色處理。從根節點開始,將根節點(深度為1)染色為Red,然後進行BFS遍歷,和根節點直接相連的節點(深度為2)染色為Blue。然後與這些節點相連的節點(深度為1、2或3),便存在兩種不同的情況:未染色的點和已染色的點;對於未染色的點(深度為3)我們將其染色為Red即可,但對於已染色的點,若該節點的顏色為Blue(深度為2),則說明該節點根節點相連,即深度為2的節點中存在直接相連的兩個點,則該圖不能劃分為二部圖程式終止即可;若該節點的顏色為Red,則表明該節點即為根節點(深度為1),不進行任何操作,可以繼續正常遍歷。在整個計算過程中,若程式沒有中途退出,則表明該圖可以劃分為二部圖。簡單來說: 在染色的過程中,對於節點V(已染色),若與其相連的節點U為染色,則將U染色為異色即可;若U已染色且其顏色與V不同,則不需要進行操作;若U已染色且顏色與V相同,則提前終止程式。

程式碼實現

此演算法我才用go語言實現:

func isBipartite(graph [][]int) bool {
	// Graph 儲存圖、Color儲存染色狀態
    Graph := make(map[int][]int)
    var Color [150]int
    for index, _ := range Color {	// 初始化Color
        Color[index] = -1
    }
    for node, edges := range graph {
        Graph[node] = edges
    }
	// 最外層迴圈:輸入資料可能存在多個聯通分量的情況,即圖可能並不連通;所以需要處理每個聯通分量
    for index, _ :=range Color {
    	// 以未染色的第一個節點為根節點開始BFS
        if Color[index] == -1 {
        	// 利用佇列模擬BFS
            queue := make([]int, 0)
            queue = append(queue, index)
            head := 0
            // 0,1代表Red和Blue
            Color[index] = 0
            for head < len(queue) {
            	// 遍歷與queue[head]相連的所有節點並進行判斷
                for _, edge := range Graph[queue[head]] {
                    if Color[edge] == -1 {
                        Color[edge] = 1 - Color[queue[head]]
                        queue = append(queue, edge)
                    } else if Color[edge] == Color[queue[head]] {
                        return false
                    }
                }
                head++
            }
        }
    }
    return true
}

遇到的問題

最初程式碼並沒有考慮圖不連通的情況,所以對於多聯通分量並不能通過測試: 在這裡插入圖片描述