[785].判斷二分圖

判斷二分圖

 


題目

給定一個無向圖graph,當這個圖爲二分圖時返回true

如果我們能將一個圖的節點集合分割成兩個獨立的子集AB,並使圖中的每一條邊的兩個節點一個來自A集合,一個來自B集合,我們就將這個圖稱爲二分圖。

graph將會以鄰接表方式給出,graph[i]表示圖中與節點i相連的所有節點。每個節點都是一個在0graph.length-1之間的整數。

這圖中沒有自環和平行邊:graph[i] 中不存在i,並且graph[i]中沒有重複的值。

示例 1:

輸入: [[1,3], [0,2], [1,3], [0,2]]
輸出: true
解釋: 
無向圖如下:
0----1
|    |
|    |
3----2
我們可以將節點分成兩組: {0, 2}{1, 3}

示例 2:

輸入: [[1,2,3], [0,2], [0,1,3], [0,2]]
輸出: false
解釋: 
無向圖如下:
0----1
| \  |
|  \ |
3----2
我們不能將節點分割成兩個獨立的子集。

 


函數原型

C的函數原型:

bool isBipartite(int** graph, int graphSize, int* graphColSize){}

 


邊界判斷

注意:

graph 的長度範圍爲 [1, 100]。
graph[i] 中的元素的範圍爲 [0, graph.length - 1]。
graph[i] 不會包含 i 或者有重複的值。
圖是無向的: 如果j 在 graph[i]裏邊, 那麼 i 也會在 graph[j]裏邊。

上面明確了 graph 的訪問,並不存在 0 的情況,所以,這裏並不需要邊界判斷。

 


算法設計:DFS

思路:用 DFS 進行染色,在二分圖的情況下,可以使用貪心思想給圖着色:一個節點爲藍色,說明它的所有鄰接點爲紅色,它的鄰接點的所有鄰接點爲藍色,依此類推。

  • 使用 DFS 做二分圖檢測,需要不斷對沒有遍歷過的頂點進行染色,對遍歷過的頂點,查看是否矛盾。

  • 如果產生矛盾,即某條邊的兩個端點顏色一樣,則說明整張圖不可能是二分圖,否則,整張圖就是二分圖。

  • 用一個 visited 數組記錄是否訪問過了,再用一個 colors 數組記錄染色,但如果只是二分圖的話,因爲只有倆種顏色,所以只需要用一個 colors 數組即可。

bool dfs(int **graph, int size, int *col, int *color, int v,  int set)
{
    for (int j = 0; j < col[v]; j++) {                   // 遍歷頂點 v 所有相鄰的點
        if ( color[graph[v][j]] == 0 ) {                 // 如果當前鄰點沒有訪問過
             color[graph[v][j]] = (set == 'r' ? 'b' : 'r');    
            // 若當前鄰點的顏色是 'r'(紅色),改爲 'b'(藍色),否則 'r'(紅色)  --> 保證頂點 v 和頂點 v 所有相鄰點的顏色不同
            if ( !dfs(graph, size, col, color, graph[v][j], color[graph[v][j]]) ) {
                return false;
            }
        } else {
            if ( color[graph[v][j]] == set ) {           // 頂點顏色相同,出現矛盾
                return false;
            }
        }
    }

    return true;
}

bool isBipartite(int** graph, int graphSize, int* graphColSize)
{
    int *color = malloc(sizeof(int) * graphSize);
    memset(color, 0, sizeof(int) * graphSize);

    for (int i = 0; i < graphSize; i++) {
        if (color[i] == 0) {    // color 當做標記數組 visited,等於0 表示還沒訪問
            color[i] = 'r';     // 標記爲已訪問,並標記爲 'r'(紅色)
            if ( !dfs(graph, graphSize, graphColSize, color, i, 'r') ) {
                // 把頂點 i 的 顏色傳過去,如果 dfs==false,那就不是二分圖。
                return false;
            }
        }
    }

    return true;
}

DFS的複雜度:

  • 時間複雜度:Θ(n)\Theta(n)
  • 空間複雜度:Θ(1)\Theta(1)
     

算法設計:BFS

思路:和 DFS 的思路一樣。

bool isBipartite(int** graph, int graphSize, int* graphColSize){
    int* colors = (int*)malloc(graphSize * sizeof(int));
    memset(colors, 0, graphSize * sizeof(int));

    // 模擬隊列
    int* pQueue = (int*)malloc(graphSize * sizeof(int));
    int front = -1;  // 隊尾
    int rear = -1;   // 隊頭
    int v = 0;       // 頂點v
    int set = 0;     // 顏色,0爲未定義+未訪問

    for (int i = 0; i < graphSize; i++)
    {   
        if (0 != colors[i])
            continue;

        pQueue[++rear] = i;
        colors[i] = 'r';

        while (front != rear)
        {   
            v = pQueue[++front];                        // 入隊
            set = (colors[v] == 'r' ? 'b' : 'r');

            for (int j = 0; j < graphColSize[v]; j++)
            {
                if (0 == colors[graph[v][j]]){
                    colors[graph[v][j]] = set;
                    pQueue[++rear] = graph[v][j];       // 出隊
                }else if (set != colors[graph[v][j]])   
                    return false;
            }
        }
    }
    free(colors);
    return true;
}

BFS的複雜度:

  • 時間複雜度:Θ(n2)\Theta(n^{2})
  • 空間複雜度:Θ(n)\Theta(n)
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章