题目
给定一组 n 人(编号为 1, 2, ..., n), 我们想把每个人分进任意大小的两组。每个人都可能不喜欢其他人,那么他们不应该属于同一组。
给定整数 n 和数组 dislikes ,其中 dislikes[i] = [ai, bi] ,表示不允许将编号为 ai 和 bi的人归入同一组。当可以用这种方法将所有人分进两组时,返回 true;否则返回 false。
来源:力扣(LeetCode) 链接:力扣 著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
解题思路
贪心法(错误)
先向一个组合内进行尽可能地插入,不能插入当前组合的放入另一个集合,之后判断另一个集合里面的元素是否会发生排斥。
class Solution {
public:
bool possibleBipartition(int n, vector<vector<int>>& dislikes) {
unordered_map<int, unordered_set<int>> i2dislike;
sort(dislikes.begin(), dislikes.end(), [](const auto& a, const auto& b){
return a[0] < b[0];
});
int dislikeSize = dislikes.size();
for(int i=0; i<dislikeSize; i++){
i2dislike[dislikes[i][0]].insert(dislikes[i][1]);
}
unordered_set<int> cantAddA;
for(int i=1; i<=n; i++){
if (cantAddA.count(i) == 1){
continue;
}else{
for(int t: i2dislike[i]){
cantAddA.insert(t);
}
}
}
unordered_set<int> cantAddB;
for(auto it = cantAddA.begin(); it != cantAddA.end(); it++){
int i = *it;
if (cantAddB.count(i) == 1){
return false;
}else{
for(int t: i2dislike[i]){
cantAddB.insert(t);
}
}
}
return true;
}
};
错误原因
考虑dislike
组合:[1,3], [3, 4], [4, 2]
根据贪心算法,我们会先加入[1, 2]之后[3, 4]无法插入,且[3, 4]内存在排斥;
但是[1, 4]和[3, 2]是合法。
出现错误的原因是,我们将一个不受限制的元素2默认插入到[1]中,但是2也能不放入[1],放到另一个集合中。我们没有考虑这种情况。
深度优先搜索
-
插入某个节点后,我们将其互斥的节点插入到另一个分组中;
-
递归进行这个步骤,
结束条件:
-
存在互斥节点没有分组,return 递归(互斥节点)
-
没有互斥的节点,return true;
-
互斥的节点被插入另一组,continue;
-
互斥的节点被插入同一组,return false;
为什么这里一旦发现互斥节点插入同一组就不行呢?
因此我们是按照dislike
进行递归的,所有dislike
的节点必须处在另一组,我们没有考虑不受控的节点,例如上个例子中的2。
上个例子的递归步骤是:
第一组 | 第二组 | |
---|---|---|
递归入口 | 1->(3) | |
1 | 3->(4) | |
1,4->(2) | 3 | |
3, 2 |
class Solution {
public:
bool dfs(int curnode, int nowcolor, vector<int>& color, const vector<vector<int>>& g) {
// color[i] = 0 / 01 / 10
color[curnode] = nowcolor;
parts[nowcolor].push_back(curnode);
for (auto& nextnode : g[curnode]) { // 当前节点排斥的节点
// 排斥的节点已经被分到同一组
if (color[nextnode] && color[nextnode] == color[curnode]) {
return false;
}
// 排斥的节点没有分组,将其分到另一组
if (!color[nextnode] && !dfs(nextnode, 3 ^ nowcolor, color, g)) {
return false;
}
}
return true;
}
bool possibleBipartition(int n, vector<vector<int>>& dislikes) {
vector<int> color(n + 1, 0);
vector<vector<int>> g(n + 1);
for (auto& p : dislikes) {
g[p[0]].push_back(p[1]);
g[p[1]].push_back(p[0]);
}
for (int i = 1; i <= n; ++i) {
if (color[i] == 0 && !dfs(i, 1, color, g)) {
return false;
}
}
return true;
}
};