정답 코드 및 풀이는 맨 아래에 있습니다.
https://www.acmicpc.net/problem/1707
- 이분 그래프의 개념만 익힌다면 수월하게 구상, 구현할 수 있다.
< 이분 그래프 >
[문제]
그래프의 정점의 집합을 둘로 분할하여, 각 집합에 속한 정점끼리는 서로 인접하지 않도록 분할할 수 있을 때, 그러한 그래프를 특별히 이분 그래프 (Bipartite Graph)라 부른다.
그래프가 입력으로 주어졌을 때, 이 그래프가 이분 그래프인지 아닌지 판별하는 프로그램을 작성하시오.
[입력]
입력은 여러 개의 테스트 케이스로 구성되어 있는데, 첫째 줄에 테스트 케이스의 개수 K가 주어진다. 각 테스트 케이스의 첫째 줄에는 그래프의 정점의 개수 V와 간선의 개수 E가 빈 칸을빈칸을 사이에 두고 순서대로 주어진다. 각 정점에는 1부터 V까지 차례로 번호가 붙어 있다. 이어서 둘째 줄부터 E개의 줄에 걸쳐 간선에 대한 정보가 주어지는데, 각 줄에 인접한 두 정점의 번호 u, v (u ≠ v)가 빈칸을 사이에 두고 주어진다.
[출력]
K개의 줄에 걸쳐 입력으로 주어진 그래프가 이분 그래프이면 YES, 아니면 NO를 순서대로 출력한다.
[제한]
- 2 ≤ K ≤ 5
- 1 ≤ V ≤ 20,000
- 1 ≤ E ≤ 200,000
예제 입력 | 예제 출력 |
2 3 2 1 3 2 3 4 4 1 2 2 3 3 4 4 2 |
YES NO |
아이디어
우선 이분 그래프라는 것을 이해해야 한다. 문제에 다음과 같이 나와있다. 이게 무슨 의미냐하면
그래프의 정점의 집합을 둘로 분할하여, 각 집합에 속한 정점끼리는 서로 인접하지 않도록 분할할 수 있을 때, 그러한 그래프를 특별히 이분 그래프 (Bipartite Graph)라 부른다.
사진 출처 : https://gmlwjd9405.github.io/2018/08/23/algorithm-bipartite-graph.html
다음 그림처럼 인접하지 않은 노드그룹 두 개로 나눌 수 있는 그래프가 이분 그래프이다.
즉, 인접한 노드끼리는 다른 그룹에 속하게 할 수 있다면 그 그래프는 이분 그래프인 것이다. 따라서 노드에 하나씩 접근할 때마다 이전에 접근한 노드와 다른 그룹을 배치시켜 주면 된다. dfs와 bfs 모두 풀 수 있는 문제 같다. 나는 bfs만 풀어왔기 때문에 dfs연습할 겸 dfs로 풀었다.
풀이 및 코드
import sys
sys.setrecursionlimit(1000000)
def dfs(now):
for next in graph[now]:
# 아직 접근 안했으면 접근
if visited[next] == 0:
# 반대되는 색 칠해줌
visited[next] = -1 * visited[now]
# dfs를 하나 더 호출하고, 만약 그 호출한 함수가 False를 리턴한다면 지금 이 함수도 False 리턴.
if not dfs(next):
return False
# 인접한 점이 같으면 잘못된 것. -> False 리턴
elif visited[next] == visited[now]:
return False
return True
k = int(sys.stdin.readline())
for _ in range(k):
# 초기 세팅
v, e = map(int, sys.stdin.readline().split())
graph = [[] for _ in range(v + 1)]
# visited에는 1 혹은 -1로 색 구분함
visited = [0 for _ in range(v + 1)]
for _ in range(e):
a, b = map(int, sys.stdin.readline().split())
graph[a].append(b)
graph[b].append(a)
# 모든 노드에 접근
for i in range(1, v + 1):
if visited[i] == 0:
# 아직 접근 하지 않았다면 1로 설정(임의로 아무거나 설정하는 것임.)
visited[i] = 1
if not dfs(i):
print("NO")
break
else :
print("YES")
dfs 함수는 한 노드에서 접근하지 않은 인접한 노드가 더 이상 없을 때까지 계속해서 접근하고, 접근할 때마다 이전의 노드와는 다른 색을 칠해주는 함수이다. 두 개의 분리된 그래프가 있을 수도 있다. 이럴 땐 두 그래프가 모두 이분 그래프라면 그 그래프는 이분 그래프이다. (같은 색 그룹끼리 묶어주면 서로 인접하지 않는 두 그룹으로 나뉘므로) 따라서 for문을 통해 모든 노드에 접근해 주는 것이다.
후기
나는 자꾸 시간초과가 뜨길래 알고리즘상에 오류가 있는 줄 알았다. 한 시간 넘게 고민한 끝에 입력이 너무 반복되어서 시간초과가 나는 것이라는 걸 깨달았다. 입력이 많을 땐 input()보다 sys.stdin.readline()으로 입력을 받는 것이 훨씬 빠르게 동작한다. 이 점 주의하자!
'공부 > 백준' 카테고리의 다른 글
[백준] 10816번 숫자 찾기 (Python) (0) | 2023.02.15 |
---|---|
[백준] 1920번 수 찾기 (Python) (0) | 2023.02.14 |
[백준] 2206번 벽 부수고 이동하기 (Python) (0) | 2023.02.01 |
[백준] 7576번 토마토 (Python) (0) | 2023.01.31 |
[백준] 2606번 바이러스 (Python) (0) | 2023.01.30 |