백준 / 10026번 적록색약 (DFS,BFS) / Python 파이썬

2023. 5. 19. 11:00·coding test - python/백준
728x90
반응형

 

*문제 출처는 백준에 있습니다.

문제 제목: 10026번 적록색약

문제 사이트: https://www.acmicpc.net/problem/10026

 

10026번: 적록색약

적록색약은 빨간색과 초록색의 차이를 거의 느끼지 못한다. 따라서, 적록색약인 사람이 보는 그림은 아닌 사람이 보는 그림과는 좀 다를 수 있다. 크기가 N×N인 그리드의 각 칸에 R(빨강), G(초록)

www.acmicpc.net

한국어   
시간 제한메모리 제한제출정답맞힌 사람정답 비율
1 초 128 MB 50388 28969 22173 56.500%

문제

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

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

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

RRRBB
GGBBB
BBBRR
BBRRR
RRRRR

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

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

입력

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

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

출력

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

예제 입력 1 복사

5
RRRBB
GGBBB
BBBRR
BBRRR
RRRRR

예제 출력 1 복사

4 3

출처

Olympiad > USA Computing Olympiad > 2013-2014 Season > USACO March 2014 Contest > Bronze 3번

  • 문제를 번역한 사람: baekjoon
  • 어색한 표현을 찾은 사람: corea

알고리즘 분류

  • 그래프 이론
  • 그래프 탐색
  • 너비 우선 탐색
  • 깊이 우선 탐색

 


나의 풀이 (첫번째 풀이 - 시간초과, DFS)

 

첫번째 정상인 사람의 시야에서 봤을 때 DFS 탐색 결과 총 영역을 알아낸 뒤,

적록색약이 보았을 때의 시야로 (빨강, 초록 -> 모두 빨강으로 처리)  DFS 탐색 결과 총 영역을 알아내었다.

import sys
sys.setrecursionlimit(1000000)
visited = []
type_1 = 0
type_2 = 1

def dfs(y,x,type_,m):
    global visited
    direct = [(1,0),(-1,0),(0,1),(0,-1)] # 상 하 좌 우
    if [y,x,type_] not in visited:
        visited.append([y,x,type_])
        for i in range(4):
            yy = y + direct[i][0]
            xx = x + direct[i][1]
            if 0 <= xx < n and 0 <= yy < n and m[yy][xx] == m[y][x]:
                dfs(yy,xx,type_,m)
    else:
        return

def search(n,m,type_):
    global visited
    cnt = 0
    for i in range(n):
        for j in range(n):
            if [i,j,type_] not in visited:
                dfs(i,j,type_,m)
                cnt += 1
    return cnt
if __name__ == "__main__":
    input = sys.stdin.readline

    n = int(input())

    maps = []
    for i in range(n):
        m = input().strip("\n")
        maps.append(list(m))
    
    cnt1 = search(n,maps,type_1)
    
    c_maps = list(maps) # 적록색약의 시야
    for i in range(len(c_maps)):
        for j in range(len(c_maps[i])):
            if c_maps[i][j] == "G":
                c_maps[i][j] = "R"
                
    cnt2 = search(n,c_maps,type_2)
    print(cnt1,cnt2)

 

두번째 풀이

방문처리하는 것을 

if not in 에서 3차원 리스트로 변경하여 해당 인덱스의 방문처리가 True 인지 False인지 검사하고, 

False 이면 해당 좌표를 방문하도록 하였다.

visited = [[False for _ in range(n)] for _ in range(n)] * 2
def dfs(y,x,type_,m):
    global visited
    direct = [(1,0),(-1,0),(0,1),(0,-1)] # 상 하 좌 우
    if visited[type_][i][j] == False :
        visited[type_][i][j] = True # 방문처리
        for i in range(4):
            yy = y + direct[i][0]
            xx = x + direct[i][1]
            if 0 <= xx < n and 0 <= yy < n and m[yy][xx] == m[y][x]:
                dfs(yy,xx,type_,m)
    else:
        return

해당 코드 처럼 수정하여서 아래에 최종코드로 제출함

 

import sys
sys.setrecursionlimit(1000000)
type_1 = 0 # 정상인 
type_2 = 1 # 적록색약 

def dfs(y,x,type_,m):
    global visited
    direct = [(1,0),(-1,0),(0,1),(0,-1)] # 상 하 좌 우
    if visited[type_][i][j] == False :
        visited[type_][i][j] = True # 방문처리
        for i in range(4):
            yy = y + direct[i][0]
            xx = x + direct[i][1]
            if 0 <= xx < n and 0 <= yy < n and m[yy][xx] == m[y][x]:
                dfs(yy,xx,type_,m)
    else:
        return

def search(n,m,type_):
    global visited
    cnt = 0
    for i in range(n):
        for j in range(n):
            if visited[type_][i][j] == False :
                dfs(i,j,type_,m)
                cnt += 1
    return cnt
if __name__ == "__main__":
    input = sys.stdin.readline

    n = int(input())
    visited = [[False for _ in range(n)] for _ in range(n)] * 2
    maps = []
    for i in range(n):
        m = input().strip("\n")
        maps.append(list(m))
    
    cnt1 = search(n,maps,type_1)
    
    c_maps = list(maps) # 적록색약의 시야
    for i in range(len(c_maps)):
        for j in range(len(c_maps[i])):
            if c_maps[i][j] == "G":
                c_maps[i][j] = "R"
                
    cnt2 = search(n,c_maps,type_2)
    print(cnt1,cnt2)

결론

  1. 우선 적록색맹이 아닐 때 영역의 개수를 구한다.
  2. R을 G로 바꿔준다.
  3. 적록색맹일 때 영역의 개수를 구한다.

다른 풀이 (BFS)

from collections import deque

def BFS(x,y):
    q.append((x,y))
    dx = [-1,0,1,0]
    dy = [0,1,0,-1]
    visited[x][y] = 1
    while q:
        x, y = q.popleft()
        for d in range(4):
            nx = x + dx[d]
            ny = y + dy[d]
            # 인덱스 범위 안에 있으면서, 같은 색이면서, 방문 안한 경우
            if 0<=nx<N and 0<=ny<N and a[nx][ny] == a[x][y] and not visited[nx][ny]:
                visited[nx][ny] = 1  # 방문체크 후 큐에 넣음
                q.append((nx,ny))


N = int(input())
a = [list(input()) for _ in range(N)]
q = deque()

# 적록색약 아닌 경우
visited = [[0] * N for _ in range(N)]
cnt1 = 0
for i in range(N):
    for j in range(N):
        if not visited[i][j]:  # 아직 방문 안한 경우만 체킹
            BFS(i,j)
            cnt1 += 1

# 적록색약인 경우
for i in range(N):
    for j in range(N):
        if a[i][j] == 'G':
            a[i][j] = 'R'

visited = [[0] * N for _ in range(N)]
cnt2 = 0
for i in range(N):
    for j in range(N):
        if not visited[i][j]:
            BFS(i,j)
            cnt2 += 1

print(cnt1, cnt2)

※ 알아야 할 것

- sys.setrecursionlimit(1000000) :재귀 함수의 최대 깊이를 1000000으로 설정

- 방문처리는 1차원이 아닌 좌표값의 방문처리를 확인할 수 있도록 2차원이나 3차원으로 나타내는 것이 효율적 (인덱스 접근이므로)

 

728x90
반응형

'coding test - python > 백준' 카테고리의 다른 글

백준 / 7576번 토마토 (2차원 BFS) / Python 파이썬  (1) 2023.05.19
백준 / 2630번 색종이 만들기 - 재귀 / Python 파이썬  (1) 2023.05.19
백준 / 1389번 케빈 베이컨의 6단계 법칙 - 최단경로알고리즘, 플로이드워셜 / Python 파이썬  (0) 2023.05.19
백준 / 7569번 토마토 - BFS / Python 파이썬  (0) 2023.05.18
백준 / 1107번 리모컨 / Python 파이썬  (0) 2023.05.16
'coding test - python/백준' 카테고리의 다른 글
  • 백준 / 7576번 토마토 (2차원 BFS) / Python 파이썬
  • 백준 / 2630번 색종이 만들기 - 재귀 / Python 파이썬
  • 백준 / 1389번 케빈 베이컨의 6단계 법칙 - 최단경로알고리즘, 플로이드워셜 / Python 파이썬
  • 백준 / 7569번 토마토 - BFS / Python 파이썬
sillon
sillon
꾸준해지려고 합니다..
    반응형
  • sillon
    sillon coding
    sillon
  • 전체
    오늘
    어제
    • menu (614)
      • notice (2)
      • python (68)
        • 자료구조 & 알고리즘 (23)
        • 라이브러리 (19)
        • 기초 (8)
        • 자동화 (14)
        • 보안 (1)
      • coding test - python (301)
        • Programmers (166)
        • 백준 (76)
        • Code Tree (22)
        • 기본기 문제 (37)
      • coding test - C++ (5)
        • Programmers (4)
        • 백준 (1)
        • 기본기문제 (0)
      • 공부정리 (5)
        • 신호처리 시스템 (0)
        • Deep learnig & Machine lear.. (41)
        • Data Science (18)
        • Computer Vision (17)
        • NLP (40)
        • Dacon (2)
        • 모두를 위한 딥러닝 (강의 정리) (4)
        • 모두의 딥러닝 (교재 정리) (9)
        • 통계 (2)
      • HCI (23)
        • Haptics (7)
        • Graphics (11)
        • Arduino (4)
      • Project (21)
        • Web Project (1)
        • App Project (1)
        • Paper Project (1)
        • 캡스톤디자인2 (17)
        • etc (1)
      • OS (10)
        • Ubuntu (9)
        • Rasberry pi (1)
      • App & Web (9)
        • Android (7)
        • javascript (2)
      • C++ (5)
        • 기초 (5)
      • Cloud & SERVER (8)
        • Git (2)
        • Docker (1)
        • DB (4)
      • Paper (7)
        • NLP Paper review (6)
      • 데이터 분석 (0)
        • GIS (0)
      • daily (2)
        • 대학원 준비 (0)
      • 영어공부 (6)
        • job interview (2)
  • 블로그 메뉴

    • 홈
    • 태그
    • 방명록
  • 링크

  • 공지사항

  • 인기 글

  • 태그

    백준
    소수
    programmers
    Python
  • 최근 댓글

  • 최근 글

  • hELLO· Designed By정상우.v4.10.3
sillon
백준 / 10026번 적록색약 (DFS,BFS) / Python 파이썬
상단으로

티스토리툴바