https://www.acmicpc.net/problem/2573
2573번: 빙산
첫 줄에는 이차원 배열의 행의 개수와 열의 개수를 나타내는 두 정수 N과 M이 한 개의 빈칸을 사이에 두고 주어진다. N과 M은 3 이상 300 이하이다. 그 다음 N개의 줄에는 각 줄마다 배열의 각 행을
www.acmicpc.net
📌 시간을 많이 쓴 이유
시간초과를 해결하느라 시간을 좀 많이 썼다..
pypy3 으로 제출해도 시간초과가 나서 음..큰일났네 생각하고 문제점을 찾기 시작했다.
시간초과 해결순서
iceberg_melts() 라는 함수를 만들어서 1년마다 그래프를 돌면서 상하좌우에 0이 있으면 -1 을 해준다 ->
visited 2차원 배열을 만들어서 중복해서 녹일수 없도록 한다 ->
year를 1증가지키고 덩어리의 수를 찾기 위해서 bfs 탐색을 시작한다 ->
group_cnt 가 1 보다 그면 year 출력 후 종료
📌 시간초과 코드
from collections import deque
import sys
input = sys.stdin.readline
def iceberg_melts():
for x in range(row):
for y in range(col):
if iceberg[x][y] > 0:
visited[x][y] = True
for i in range(4):
nx = x + dx[i]
ny = y + dy[i]
if (
0 <= nx < row
and 0 <= ny < col
and iceberg[nx][ny] == 0
# 현재 빙하에서 상하좌우에 있는 빙하중에 같은 해에 녹아서 0이 되버린 빙하에 영향을 받으면 안되므로 따로 방문처리를 해준다.
and not visited[nx][ny]
):
if iceberg[x][y] >= 1:
iceberg[x][y] -= 1
def bfs(x, y):
que = deque()
que.append((x, y))
visited[x][y] = True
while que:
x, y = que.popleft()
for i in range(4):
nx = x + dx[i]
ny = y + dy[i]
if (
0 <= nx < row
and 0 <= ny < col
and iceberg[nx][ny] > 0
and not visited[nx][ny]
):
visited[nx][ny] = True
que.append((nx, ny))
if __name__ == "__main__":
row, col = map(int, input().split())
iceberg = [list(map(int, input().split())) for _ in range(row)]
year = 0
dx = [0, 0, 1, -1]
dy = [1, -1, 0, 0]
while True:
group_cnt = 0
visited = [[False] * col for _ in range(row)]
# 시간초과의 원인, bfs 안에서 한번에 해결할 수 있다.
iceberg_melts()
year += 1
# 덩어리의 수를 구하는 bfs 를 호출하기 전에 방문처리 2차원 배열을 다시 초기화 해준다.
visited = [[False] * col for _ in range(row)]
for i in range(row):
for j in range(col):
if iceberg[i][j] > 0 and not visited[i][j]:
group_cnt += 1
bfs(i, j)
if group_cnt == 0:
print(0)
break
if group_cnt >= 2:
print(year)
break
위의 해결순서에서 아마 iceberg_melts() 함수를 계속해서 호출하는것이 시간초과의 원인이였던 것 같다.
bfs 탐색을 한번 해주면 1년에 빙산을 얼마나 녹일지와 덩어리의 수를 한번에 찾을 수 있었다!
bfs 안에서 빙산을 녹일수 있는 높이를 저장해두는 배열을 추가로 만들면 시간초과 코드처럼 방문처리를 해주지 않아도 돼서 더 효율적으로 풀 수 있다.
📌 코드
from collections import deque
import sys
input = sys.stdin.readline
def bfs(x, y):
que = deque()
que.append((x, y))
visited[x][y] = True
while que:
x, y = que.popleft()
for i in range(4):
nx = x + dx[i]
ny = y + dy[i]
if iceberg[nx][ny] > 0 and not visited[nx][ny]:
visited[nx][ny] = True
que.append((nx, ny))
elif iceberg[nx][ny] == 0:
melt_count[x][y] += 1
if __name__ == "__main__":
row, col = map(int, input().split())
iceberg = [list(map(int, input().split())) for _ in range(row)]
year = 0
dx = [0, 0, 1, -1]
dy = [1, -1, 0, 0]
while True:
group_cnt = 0
melt_count = [[0] * col for _ in range(row)]
visited = [[False] * col for _ in range(row)]
for i in range(row):
for j in range(col):
if iceberg[i][j] > 0 and not visited[i][j]:
group_cnt += 1
bfs(i, j)
if group_cnt == 0:
print(0)
break
if group_cnt > 1:
print(year)
break
# 덩어리의 수가 1개이면 year을 1년 증가 시키고 다음 탐색 진행.
for i in range(row):
for j in range(col):
iceberg[i][j] -= melt_count[i][j]
if iceberg[i][j] < 0:
iceberg[i][j] = 0
year += 1
🧐 짚고 넘어가자
녹일 수 있는 빙산의 높이를 저장해두는 2차원 배열을 따로 만드는것을 생각해내는게 이 문제를 푸는 핵심인것 같다.
빙산을 모두 녹이려면 높이가 있는 빙산을 모두 방문해야한다.
bfs 탐색도 마찬가지로 덩어리의 수를 세려면 높이가 있는 빙산을 모두 방문해야한다.
그렇다면 이 두개를 하나의 함수에서 묶어서 해결할 수 있지 않을까..? 라는 생각을 문제 풀면서 해봤으면 어땠을까 싶다..
앞으로 반복된 작업을 하나의 함수에서 해결할 수 있도록 생각해보면서 그래프 탐색을 풀어봐야겠다 !!
'algorithm > Graph Search' 카테고리의 다른 글
백준 2636 치즈 (0) | 2022.11.23 |
---|---|
백준 5014 스타트링크 (0) | 2022.11.03 |
백준 13549 숨바꼭질 3 (0) | 2022.10.10 |
백준 2583 영역 구하기 (0) | 2022.10.10 |
백준 14889 스타트와 링크 (0) | 2022.09.16 |