1. 程式人生 > >Possible Bipartition 可能的二分法

Possible Bipartition 可能的二分法

給定一組 N 人(編號為 1, 2, ..., N), 我們想把每個人分進任意大小的兩組。

每個人都可能不喜歡其他人,那麼他們不應該屬於同一組。

形式上,如果 dislikes[i] = [a, b],表示不允許將編號為 a 和 b 的人歸入同一組。

當可以用這種方法將每個人分進兩組時,返回 true;否則返回 false

示例 1:

輸入:N = 4, dislikes = [[1,2],[1,3],[2,4]]
輸出:true
解釋:group1 [1,4], group2 [2,3]

示例 2:

輸入:N = 3, dislikes = [[1,2],[1,3],[2,3]]
輸出:
false

示例 3:

輸入:N = 5, dislikes = [[1,2],[2,3],[3,4],[4,5],[1,5]]
輸出:false

提示:

  1. 1 <= N <= 2000
  2. 0 <= dislikes.length <= 10000
  3. 1 <= dislikes[i][j] <= N
  4. dislikes[i][0] < dislikes[i][1]
  5. 對於 dislikes[i] == dislikes[j] 不存在 i != j 

思路:這道題的解題思路和Is Graph Bipartite 判斷二分圖完全一樣,分別可以採用DFS和BSF來做,下面分別介紹這兩種做法。

無論是用BFS還是DFS,我們都需要把題意轉化成圖結構,首先這是一個無向邊圖,所以我們構建鄰接表時要注意,其次這裡的dislike其實就是邊的組合,我們在染色的時候出現在dislike中的組合就應該染成不同的顏色。無論DFS還是BFS,規定以下顏色規律:-1未染色,0灰色,1黑色

方法一:BFS,在一次BFS中,對於每個節點,我們首先判斷其是否未染色,只有未染色才進入,然後需要一個輔助佇列q,把當前節點放入輔助佇列中,如果佇列不為空,則取出佇列的首元素,染成0號顏色(初始狀態),然後對於其鄰接點,全部染成其他號顏色,如果遇到某鄰接點已經是其他號顏色,直接返回false,如果已經染成其他號顏色則跳過。對於染成其他號顏色的節點放入佇列中,一直迴圈。

參考程式碼:

class Solution {
public:
vector<unordered_set<int>> make_graph(vector<vector<int>>& dislikes, int N) {
	vector<unordered_set<int>> graph(N + 1);
	for (int i = 0; i < dislikes.size(); i++) {
		graph[dislikes[i][0]].insert(dislikes[i][1]);
		graph[dislikes[i][1]].insert(dislikes[i][0]);
	}
	return graph;
}
bool possibleBipartition(int N, vector<vector<int>>& dislikes) {
	vector<int> colors(N + 1, -1);
	vector<unordered_set<int>> graph = make_graph(dislikes, N);
	queue<int> q;
	for (int i = 1; i <= N; i++) {
		if (!graph[i].empty() && colors[i] == -1) {
			q.push(i);
			colors[i] = 0;
			while (!q.empty()) {
				auto source = q.front(); q.pop();
				for (auto neibor : graph[source]) {
					if (colors[neibor] != -1 && colors[neibor] == colors[source]) return false;
					if (colors[neibor] == -1) {
						colors[neibor] = colors[source] == 0 ? 1 : 0;
						q.push(neibor);
					}
				}
			}
		}
	}
	return true;        
    }
};

方法二:DFS,

對於每個節點:

  1. 如果他還沒有被染色,使用一個顏色去染色. 然後使用其他顏色去染色他所有的鄰接點 (DFS).
  2. 如果已經被染色了, 檢查當前的顏色是不是應該被染成的正確顏色. 
class Solution {
public:
vector<unordered_set<int>> make_graph(vector<vector<int>>& dislikes, int N) {
	vector<unordered_set<int>> graph(N + 1);
	for (int i = 0; i < dislikes.size(); i++) {
		graph[dislikes[i][0]].insert(dislikes[i][1]);
		graph[dislikes[i][1]].insert(dislikes[i][0]);
	}
	return graph;
}
bool validColor(vector<unordered_set<int>> &graph,int source,int color, vector<int> &colors) {
	if (colors[source] != -1) return colors[source] == color;
	colors[source] = color;
	for (auto neibor : graph[source]) {
		if (!validColor(graph, neibor, 1 - color, colors)) return false;
	}
	return true;
}
bool possibleBipartition(int N, vector<vector<int>>& dislikes) {
	vector<int> colors(N + 1, -1);
	vector<unordered_set<int>> graph = make_graph(dislikes, N);
	for (int i = 1; i <= N; i++) {
		if (colors[i] == -1 && !validColor(graph,i,0, colors)) {
			return false;
		}
	}
	return true;
}
};