判斷二分圖
題目
給定一個無向圖graph
,當這個圖爲二分圖時返回true
。
如果我們能將一個圖的節點集合分割成兩個獨立的子集A
和B
,並使圖中的每一條邊的兩個節點一個來自A
集合,一個來自B
集合,我們就將這個圖稱爲二分圖。
graph
將會以鄰接表方式給出,graph[i]
表示圖中與節點i
相連的所有節點。每個節點都是一個在0
到graph.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的複雜度:
- 時間複雜度:
- 空間複雜度:
算法設計: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的複雜度:
- 時間複雜度:
- 空間複雜度: