Possible Bipartition 可能的二分法
阿新 • • 發佈:2018-12-12
給定一組 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 <= N <= 2000
0 <= dislikes.length <= 10000
1 <= dislikes[i][j] <= N
dislikes[i][0] < dislikes[i][1]
- 對於
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,
對於每個節點:
- 如果他還沒有被染色,使用一個顏色去染色. 然後使用其他顏色去染色他所有的鄰接點 (DFS).
- 如果已經被染色了, 檢查當前的顏色是不是應該被染成的正確顏色.
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;
}
};