给定一组 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;
}
};