즐거운 PS 👩‍💻🥰

[백준-파이썬] 2573: 빙산

dalin❤️ 2021. 10. 8. 10:15

며칠 동안 고민 고민하고 많은 '틀렸습니다'와 '시간 초과'를 만났다..
아직도 파이썬으로는 시간 초과가 나오지만... 파이썬으로 시간 초과 안 나오는 로직은 나중에 생각하기로 하고.. pypy로는 통과했다 !!

빙산 문제 보러 가기~~

아이디어 ⭐

check 함수 -> 빙산이 두 부분 이상으로 나뉘었는지 체크
melt 함수 -> 1년마다 빙산의 각 구역을 물과 닿은 부분만큼 녹임(0까지만 녹임)
all_melt 함수 -> 모든 빙산이 녹았는지 체크하는 함수

year = 0으로 초기화하고 시작
계속 빙산이 두 덩어리로 나뉘었는지 체크함.

1) 두 덩어리로 나뉘었으면 year을 출력하고 break
2) 두 덩어리로 나뉘지 않았으면
1-1) 빙산이 다 녹았으면(두 덩어리로 나뉘는 게 불가능한 것이니까) 0을 출력하고 break
1-2) 빙산이 다 녹지 않았으면 1년 더 (year에 1을 추가하고, melt())

코드 👩‍💻

(완성 코드가 아닙니다.)

from collections import deque
import sys

input = sys.stdin.readline

N, M = map(int, input().split())
sea = []

for _ in range(N):
    sea.append(list(map(int, input().split())))

# 상우하좌
di = [-1, 0, 1, 0]
dj = [0, 1, 0, -1]


# 두 부분 이상으로 나뉘어졌는지 체크
def check():
    dq = deque()
    ch = list([0] * M for _ in range(N))
    ices_cnt = 0

    for i in range(1, N - 1):
        for j in range(1, M - 1):
            if ch[i][j] == 0 and sea[i][j] != 0:
                dq.append((i, j))
                ch[i][j] = 1
                ices_cnt += 1
                while dq:
                    i, j = dq.popleft()
                    for mode in range(4):
                        ii = i + di[mode]
                        jj = j + dj[mode]
                        if 1 <= ii < N - 1 and 1 <= jj < M - 1 and ch[ii][jj] == 0 and sea[ii][jj] != 0:
                            ch[ii][jj] = 1
                            dq.append((ii, jj))

    if ices_cnt <= 1:
        return False
    return True


# 1년마다 녹이기
def melt():
    melts = list([0] * M for _ in range(N))  # 빙산 얼마나 녹아야 하는지 저장하는 리스트

    for i in range(1, N - 1):
        for j in range(1, M - 1):
            if sea[i][j] != 0:
                # 얼마나 빙산 줄어들지
                melting_spots = 0
                for mode in range(4):
                    ii = i + di[mode]
                    jj = j + dj[mode]
                    if 0 <= ii < N and 0 <= jj < M and sea[ii][jj] == 0:
                        melting_spots += 1

                melts[i][j] = melting_spots

    # 그만큼씩 빼주기
    for i in range(1, N - 1):
        for j in range(1, M - 1):
            if sea[i][j] != 0:
                for _ in range(melts[i][j]):
                    if sea[i][j] > 0:
                        sea[i][j] -= 1


# 다 녹았는지 체크하는 함수
def all_melt():  # True or False를 리턴
    for i in range(1, N - 1):
        for j in range(1, M - 1):
            if sea[i][j] != 0:
                return False
    return True


year = 0
while True:
    if check():  # 빙산이 두 덩어리로 나눠졌으면
        print(year)
        break

    else:  # 빙산이 두 덩어리로 나눠지지 않았는데
        if all_melt():  # 빙산이 다 녹았으면
            print(0)
            break
        else:  # 빙산이 다 안 녹았으면 1년 더 !
            year += 1
            melt()

고민과 깨달음. 반성 🤔

코드를 이렇게 짜고 틀려서, 계속 고민했다..
로직은 분명히 맞는 것 같고, 테스트 케이스나 문제 게시판의 반례들은 잘 통과하는데 왜 틀리지??
나는 정말 정말 모르겠어서, 친구에게 부탁했다. 친구도 로직이 맞는 것 같은데 왜 틀리지? 하면서 1시간 가까이 봐줬다.
그래서 찾은 오류....
변수의 스코프!! 때문이었다...

check() 함수의

                    i, j = dq.popleft()
                    for mode in range(4):
                        ii = i + di[mode]
                        jj = j + dj[mode]

이 부분이다.. for i , for j 안에 있는데 또 i, j 를 쓴 것이다.. 이 부분만 고치니 맞았다!! (그런데 왜 테스트 케이스는 잘 통과한 건지 모르겠다..)

문제 풀 때는 변수 이름을 그냥 막 썼다..
그러다 보니 이런 실수를 한 것 같다 ㅠㅠ 너무 자연스럽게 쓰던 변수들이라서, 어디에서 틀렸나 찾기도 힘들었다..

앞으로는 문제 풀 때도 변수 이름을 잘 쓰도록 노력해야겠다!

728x90