Baekjoon/구현

🥇[백준] 2638 치즈 (골드3) / 구현, 시간초과 해결, 문제 아이디어

2023. 6. 22. 23:44

문제요약

나의 코드 및 설명 01 (시간초과)

  • 녹을 치즈가 더이상 없을 때까지 반복을 수행하면서 check_hole() 함수로 내부 공기의 좌표를 구하고, 치즈가 내부 공기 이외의 공기(외부 공기)와 2개 이상 맞닿아 있다면 녹을 예정인 치즈이므로, 리스트 r에 녹을 예정인 치즈의 좌표를 구하는 melt() 함수를 구현하였고, 그리드를 갱신해주도록 소스 코드를 작성했다.
  • 매 반복마다 내부 공기 좌표를 구하는 check_hole() 함수를 통해, 매우 많은 좌표를 중복해서 여러번 탐색하기 때문에 시간 초과가 발생했다.  
#공기가 치즈 내부에 있는 공기인지 체크
def check_hole(arr):
    for y in range(n):
        for x in range(m):
            cnt = 0
            #공기(0)인 좌표
            if arr[y][x] == 0:
                for i in range(4): #상하좌우
                    for k in range(1,max(n,m)): #가로,세로의 끝까지 탐색
                        nx = x + k*dx[i]
                        ny = y + k*dy[i]
                        if 0<=nx<m and 0<=ny<n:
                            if arr[ny][nx] == 1: #치즈(1)를 만난다면,
                                cnt += 1 #cnt값을 카운트 해준다.
                                break
            if cnt == 4: #cnt가 4라면, 공기가 치즈로 둘러쌓인 것, 즉 내부공기이다.
                v.append((x,y)) #리스트 v에 내부공기 좌표 저장
    return

#녹을 치즈의 좌표를 구하는 함수
def melt(arr):
    for y in range(n):
        for x in range(m):
            check = 0
            if arr[y][x] == 1:
                for i in range(4):
                    nx = x + dx[i]
                    ny = y + dy[i]
                    if 0<=nx<m and 0<=ny<n:
                        if (nx,ny) in v: #내부공기라면, 다음 방향 탐색
                            continue
                        elif arr[ny][nx] == 0:
                            check += 1 #외부 공기 카운트+1
                    if check == 2:
                        break 
            if check == 2: #밀접한 외부 공기가 2라면, 
                r.append((x,y)) #해당 치즈는 녹을 것이므로 리스트 r에 좌표 저장
    return


n, m = map(int, input().split()) #n:세로, m:가로

board = [list(map(int, input().split())) for _ in range(n)]

dx = [0,1,0,-1]
dy = [-1,0,1,0]


time = 0
while True:
    v = [] #내부에 있는 공기의 좌표 저장
    r = [] #녹아내릴 치즈의 좌표 저장
    check_hole(board)
    melt(board)
    if len(r) == 0:
        break
    while r:
        x, y = r.pop()
        board[y][x] = 0
    time += 1

print(time)

나의 코드 및 설명 02 (다른 사람의 힌트 참고)

  • 외부의 공기와 2개 이상 맞닿아있다면 녹을 치즈라는 사실을 활용해, 외부 공기를 -1로 표기해주고 2개 이상의 외부 공기와 맞닿아 있는 치즈의 좌표를 구해서 문제를 해결하였다.
  • 외부 공기 좌표 값을 -1로 바꾸는 bfs() 함수에서, 현재 좌표의 상하좌우의 좌표를 방문하게 되는데 방문할 좌표가 전체 그리드를 벗어났거나 치즈이거나 혹은 이미 방문한 좌표일 경우를 제외한 나머지 경우가 외부 공기인 경우이므로, if ~ : continue 를 활용해 조건의 나머지를 체크해주는 방식으로 코드를 작성하면 쉽다.
from collections import deque

#외부의 공기와 2개 이상 맞닿아있다면 녹을 치즈이다.

#외부 공기 좌표값을 -1로 바꿔주는 코드
def bfs(sx,sy):
    queue = deque()
    queue.append((sx,sy))
    v[sy][sx] = 1
    board[sy][sx] = -1

    while queue:
        x,y = queue.popleft()
        for i in range(4):
            nx = x+dx[i]
            ny = y+dy[i]
            ##방문처리 안할 좌표 먼저 생각하면 쉽다.
            # 범위를 벗어나거나, 치즈(1)이거나, 이미 방문 했다면 continue한다. 
            if nx<0 or ny<0 or nx>=m or ny>=n:
                continue
            else:
                if board[ny][nx] == 1 or v[ny][nx] == 1:
                    continue
                else:   
                    v[ny][nx] = 1 #방문처리
                    board[ny][nx] = -1 #외부 공기 좌표값 -1로 표시
                    queue.append((nx,ny))
    return

#녹아내릴 치즈의 좌표 구하는 코드
def melt():
    for y in range(n):
        for x in range(m):
            if board[y][x] == 1:
                cnt = 0
                for i in range(4):
                    nx = x + dx[i]
                    ny = y + dy[i]
                    if 0<=nx<m and 0<=ny<n:
                        if board[ny][nx] == -1: #외부 공기와 맞닿아있다면
                            cnt += 1 #cnt 값 +1
                if cnt >= 2: #cnt 값이 2 이상이라면, 즉 2개 이상의 외부 공기와 맞닿아 있다면
                    r.append((x,y)) #녹아내릴 치즈이므로 r에 해당 좌표 추가

n, m = map(int, input().split()) #n:세로, m:가로

board = [list(map(int, input().split())) for _ in range(n)]

dx = [0,1,0,-1]
dy = [-1,0,1,0]


r = []
time = 0
while True:
    r = []
    v = [[0]*m for _ in range(n)]
    bfs(0,0) #외부공기 -1로 표시
    melt() #녹아내릴 치즈의 좌표 구하기
    if len(r) == 0: #녹아내릴 치즈가 없다면 
        break #반복문 탈출
    while r:
        x,y = r.pop()
        board[y][x] = 0
    time += 1

print(time)

피드백

생각보다는 간단한 문제처럼 보였으나, 주어진 테스트케이스는 맞았지만 시간 초과가 발생했다. 혼자 힘으로 해결해보고 싶었으나 결국 힌트를 볼 수 밖에 없었고, 내부의 공기 좌표를 구하는 나의 생각과는 다르게 외부의 공기 좌표를 구하면 된다는 다른 사람의 아이디어를 보고 문제를 풀었다. 문제가 안풀리거나 비효율적으로 접근된다면 빠르게 다른 접근 방식을 생각해야만 하는데 아직 습관이 안되어있는 것 같다. 연습하다보면 언젠가 되겠지.. 문제를 많이 풀어봐야겠다. 

'Baekjoon > 구현' 카테고리의 다른 글

🥇[백준] 15686 치킨 배달 (골드5) / 구현, 백트래킹  (0) 2023.06.23
🥇[백준] 11559 Puyo Puyo (골드4) / 구현  (0) 2023.06.23
🥇[백준] 16234 인구 이동 (골드5) / 구현, 시간초과 해결  (0) 2023.06.22
[백준] 5212 지구 온난화 (실버2) / import copy, list2 = copy.deepcopy(list1), 다시한번 풀어보자  (0) 2023.06.16
[백준] 16918 봄버맨 (실버1) / 구현, 시뮬레이션  (0) 2023.06.15
'Baekjoon/구현' 카테고리의 다른 글
  • 🥇[백준] 15686 치킨 배달 (골드5) / 구현, 백트래킹
  • 🥇[백준] 11559 Puyo Puyo (골드4) / 구현
  • 🥇[백준] 16234 인구 이동 (골드5) / 구현, 시간초과 해결
  • [백준] 5212 지구 온난화 (실버2) / import copy, list2 = copy.deepcopy(list1), 다시한번 풀어보자
hellosonic
hellosonic
hellosonic
꾸준함
hellosonic
전체
오늘
어제
  • 분류 전체보기 (285)
    • SSAFY (4)
    • 프로그래머스 데브코스 (26)
    • Diary (1)
    • JavaScript (20)
    • ToyPJ (13)
      • Python-Django (13)
    • CS지식 (11)
      • 자료구조 (5)
      • 개발 상식 (2)
      • 네트워크 (4)
    • Baekjoon (141)
      • IM Level (57)
      • DFS와 BFS (21)
      • 백트래킹 (21)
      • DP (3)
      • 이분탐색 (4)
      • 구현 (14)
    • Programmers (13)
      • Lv1 (4)
      • Lv2 (9)
    • SWEA (SW Expert Academy) (52)
      • D1 (5)
      • D2 (7)
      • D3 (40)
    • 이코테 (4)
    • Grammar (0)

블로그 메뉴

  • 홈
  • 태그
  • 방명록
  • 글쓰기
  • 관리자

공지사항

인기 글

태그

  • 리액트 todolist
  • 구현
  • SWEA
  • 파이썬
  • 자바스크립트 기본기
  • SWEA 파이썬
  • 백준 14891
  • 파이썬 11478
  • 자바스크립트
  • 이코테
  • 코딩부트캠프
  • 프로그래머스
  • 파이썬 1269
  • 파이썬 1436
  • 백준
  • JS
  • 국비지원교육
  • SWEA/D3
  • 백준 2999
  • 백준 1157
  • SWEA D3
  • SWEA D2
  • 그리디
  • 파이썬 1946
  • 프로그래머스 데브코스
  • 백준 5212
  • 파이썬 2529
  • 프론트엔드 데브코스
  • javascript ux
  • 백준 18870

최근 댓글

최근 글

hELLO · Designed By 정상우.
hellosonic
🥇[백준] 2638 치즈 (골드3) / 구현, 시간초과 해결, 문제 아이디어
상단으로

티스토리툴바

단축키

내 블로그

내 블로그 - 관리자 홈 전환
Q
Q
새 글 쓰기
W
W

블로그 게시글

글 수정 (권한 있는 경우)
E
E
댓글 영역으로 이동
C
C

모든 영역

이 페이지의 URL 복사
S
S
맨 위로 이동
T
T
티스토리 홈 이동
H
H
단축키 안내
Shift + /
⇧ + /

* 단축키는 한글/영문 대소문자로 이용 가능하며, 티스토리 기본 도메인에서만 동작합니다.