====== 2색 색칠 ======
* 인접한 두 노드는 다른 색을 갖도록 하면서, 전체 노드들을 2가지 색으로 색칠하기.
* 일반적인 vertex k-coloring 은 NP라서 PS에서는 다룰일이 별로 없다.
===== 기본정리 =====
* 2색 색칠이 가능하다 <=> 이분그래프이다
* 그래프에 홀수길이 사이클이 없으면 2색 색칠 가능
* 트리는 사이클이 아예 없으니 당연히 가능
===== 알고리즘 =====
* 기본적으로는 그래프를 순회하면서 컬러를 지정하면 된다. 시간복잡도는 O(V+E)
* [[ps:Disjoint Set]]을 사용하는 방법도 가능하긴 하다.
* BFS에 비해 느리다.
* 하지만, incremental 하게 관리해야 할 필요가 있는 경우에는 이 방법이 필요하다
* 코드는 [[ps:problems:boj:7535]] 참고
* [[ps:2-sat]]으로 모델링해서 푸는 방법도 가능하다.
* 이건 disjoint set을 쓰는것보다도 더욱 느릴것 같기는 하다.
* 하지만 문제에 변형이 복잡하게 주어지면, 이렇게 모델링하는게 간단할수도 있을것 같긴 하다 (아직 본적은 없다)
==== 구현 ====
* 보통은 2-colorable 한지(=이분그래프인지) 여부를 찾는 태스크가 실제 coloring을 요구하는 태스크보다 더 흔하기는 하다. 그래서 is_bipartite 와 같은 함수를 따로 만드는 것도 생각해봤지만, 기각.
* 방문처리를 color를 주는것으로 처리하기 때문에, DFS나 BFS나 코드가 stack을 쓰느냐 queue를 쓰느냐를 제외하고는 그냥 똑같다. 속도는 BFS가 살짝 더 빨랐다.
* DFS는 이런식
*
def two_coloring(graph):
color = [None] * len(graph)
for source in range(len(graph)):
if color[source] is not None:
continue
stack = [source]
color[source] = True
while stack:
u = stack.pop()
color_u = color[u]
for v in graph[u]:
if color[v] is None:
color[v] = not color_u
stack.append(v)
elif color[v] == color_u:
raise ValueError('Not bipartite graph')
return color
* BFS는 이런식
*
def two_coloring(graph: Graph) -> list[bool]:
color = [None] * len(graph)
for source in range(len(graph)):
if color[source] is not None:
continue
color[source] = True
queue = collections.deque([source])
while queue:
u = queue.popleft()
col_u = color[u]
for v in graph[u]:
if color[v] is None:
color[v] = not col_u
queue.append(v)
elif color[v] == col_u:
raise ValueError(
'Graph is not 2-colorable (not bipartite).'
)
return color
==== 코드 ====
* [[:ps:teflib:graph#two_coloring|teflib.graph.two_coloring]]
==== 관련 문제 ====
* [[ps:problems:boj:1707]]: N≤20,000, M≤200,000
* [[ps:problems:boj:12893]]: N≤2,000, M≤1,000,000
* [[ps:problems:boj:7535]]: N≤2,000, M≤1,000,000