본문 바로가기
Coding Test/Baekjoon

[백준] 10026 적록색약(Python) - BFS

by ngool 2024. 8. 22.

📌 문제

적록색약은 빨간색과 초록색의 차이를 거의 느끼지 못한다. 따라서, 적록색약인 사람이 보는 그림은 아닌 사람이 보는 그림과는 좀 다를 수 있다.

크기가 N×N인 그리드의 각 칸에 R(빨강), G(초록), B(파랑) 중 하나를 색칠한 그림이 있다. 그림은 몇 개의 구역으로 나뉘어져 있는데, 구역은 같은 색으로 이루어져 있다. 또, 같은 색상이 상하좌우로 인접해 있는 경우에 두 글자는 같은 구역에 속한다. (색상의 차이를 거의 느끼지 못하는 경우도 같은 색상이라 한다)

예를 들어, 그림이 아래와 같은 경우에

RRRBB
GGBBB
BBBRR
BBRRR
RRRRR

 

적록색약이 아닌 사람이 봤을 때 구역의 수는 총 4개이다. (빨강 2, 파랑 1, 초록 1) 하지만, 적록색약인 사람은 구역을 3개 볼 수 있다. (빨강-초록 2, 파랑 1)

그림이 입력으로 주어졌을 때, 적록색약인 사람이 봤을 때와 아닌 사람이 봤을 때 구역의 수를 구하는 프로그램을 작성하시오.

입력

첫째 줄에 N이 주어진다. (1 ≤ N ≤ 100)

둘째 줄부터 N개 줄에는 그림이 주어진다.

출력

적록색약이 아닌 사람이 봤을 때의 구역의 개수와 적록색약인 사람이 봤을 때의 구역의 수를 공백으로 구분해 출력한다.

예제 입력

5
RRRBB
GGBBB
BBBRR
BBRRR
RRRRR

예제 출력

4 3

📌 풀이

Code

import sys
from collections import deque
input = sys.stdin.readline

def BFS(start_r, start_c, color):
    queue = deque()		                # 큐 생성
    queue.append([start_r, start_c])		# 시작 좌표 enqueue
    visited[start_r][start_c] = 1		# 시작 좌표 방문 표시

    while queue:
        r, c = queue.popleft()
        for k in range(4):				# 상하좌우 탐색
            nr = r + dr[k]
            nc = c + dc[k]
            # 배열을 벗어나지 않고, 방문한적 없으며, 시작점과 같은 색깔이면 큐에 넣고 방문 표시
            if 0 <= nr < N and 0 <= nc < N and not visited[nr][nc] and arr[nr][nc] in color:
                queue.append([nr, nc])    
                visited[nr][nc] = 1
    return

N = int(input())                                    # 그림 크기
arr = [list(input().strip()) for _ in range(N)]     # 그림

# 델타
dr = [0, 0, 1, -1]
dc = [1, -1, 0, 0] 

# 정상인
cnt = 0                                   # 본 구역의 개수
visited = [[0]*N for _ in range(N)]       # 방문 리스트 초기화
for r in range(N):
    for c in range(N):
        if not visited[r][c]:
            BFS(r, c, arr[r][c])
            cnt += 1
print(cnt, end=' ')
    
# 색맹
cnt = 0                                   # 본 구역의 개수
visited = [[0]*N for _ in range(N)]       # 방문 리스트 초기화
for r in range(N):
    for c in range(N):
        if not visited[r][c]:
            if arr[r][c] == 'B':		  # 파란색이면
                color = 'B'			  # 영역 탐색 대상은 파란색
            else:				  # 파란색이 아니면
                color = 'RG'			  # 영역 탐색 대상은 빨, 초
            BFS(r, c, color)
            cnt += 1    
print(cnt)

 

Solution

1. 상하좌우를 탐색할 수 있는 델타 값 만들기

 

2. 정상인(색맹이 아닌 사람)이 본 구역의 개수를 세기 위해 카운트 변수, 방문 리스트 만들기

 

3. 0행 0열부터 N-1행 N-1열까지 반복문을 순회하여 BFS 탐색 시작점 설정

 

4. 시작점의 색깔과 같은 색깔인 인접 칸만 방문 표시하는 BFS 수행

 

5. BFS 함수가 한번 끝날 때마다 카운트 1 증가 (하나의 영역에 대해 방문 표시가 완료되었다는 뜻)

 

6. 위와 같은 방식으로 색맹이 본 구역의 개수도 세기

  • 색맹의 경우, R과 G는 같은 영역으로 고려 (시작점이 R인 경우, BFS 수행 시  R, G 두 가지 색깔 인접 칸 모두에 대해 방문 표시)

 


깨달은 점

BFS를 쓰는 방법은 알았지만 어떤 경우에 써야할지 헷갈렸는데, 이번 문제를 통해 어느정도 감이 온 것 같아요!

 

그래프의 너비를 우선적으로 탐색하는 것이니,

2차원 배열에서는 가장 가까운 주변을 하나하나 탐색하며 가는 느낌이라고 보면 될 것 같네요.

 

주변을 일일이 다 보면서 사방으로 퍼져나가는 로직이 필요할 때, 앞으로 BFS를 바로 떠올려야겠습니다~