给定一组 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
dislikes[i].length == 2
1 <= dislikes[i][j] <= N
dislikes[i][0] < dislikes[i][1]
对于 dislikes[i] == dislikes[j] 不存在 i != j
因为要分到2组
意思就是有一些人不呢能分到一个组里面,然后构建二部图,把不能分到一组的人连线,连线的人不能同样的颜色。然后用bfs或DFS对图进行遍历,染色。如果正好都能染色,则可以成功分组。否则不能成功分组。
from typing import List
class Solution:
def possibleBipartition(self, N: int, dislikes: List[List[int]]) -> bool:
def bfs(graph, colors, dislike):
# 邻接表广度优先遍历
graph = [[] for _ in range(N + 1)]
colors = [0 for _ in range(N + 1)]
for dis in dislikes:
graph[dis[0] - 1].append(dis[1] - 1)
graph[dis[1] - 1].append(dis[0] - 1)
que = [] # 队列,广度优先遍历使用的, 染色,入队
for i in range(N):
if colors[i] != 0: # 当前节点染色过了,不需要染色,推出下一个结点
continue
colors[i] = 1 # 当前节点染色,结点入队
que.append(i)
while len(que) != 0: # 广度优先遍历
cur = que.pop(0)
for num in graph[cur]:
if colors[num] == colors[cur]: # 邻居颜色相等
return False
if colors[num] != 0: # 已经染过色了
continue
colors[num] = -colors[cur]
que.append(num)
return True
# 邻接表深度优先遍历
# 构建图
graph = [[] for _ in range(N+1)]
# 构建每个节点的颜色数组,共N个结点
colors_ = [0 for _ in range(N+1)]
# 构建不喜欢矩阵,然后染色,如果能正确染色,则能True分组,否则False
for dis in dislikes:
graph[dis[0]].append(dis[1])
graph[dis[1]].append(dis[0])
def dfs(pos, color):
colors_[pos] = color # 当前节点染色
for i in graph[pos]: # 深度遍历判断 我的第一个邻居不能跟我一个颜色
if colors_[i] == color:
return False
if colors_[i] == 0 and not dfs(i, -color):
# 邻居没染色,并且染相反的颜色失败。意思就是跟我一个颜色
return False
return True # 当前节点染色成功
# 遍历所有节点 因为题目中的结点从开始计数
for i in range(1, N+1): # 从第一个结点开始,判断没有染色,并且染色。dfs染色。
if colors_[i] == 0 and not dfs(i, 1):
return False
return True