https://www.acmicpc.net/problem/2573
2573번: 빙산
첫 줄에는 이차원 배열의 행의 개수와 열의 개수를 나타내는 두 정수 N과 M이 한 개의 빈칸을 사이에 두고 주어진다. N과 M은 3 이상 300 이하이다. 그 다음 N개의 줄에는 각 줄마다 배열의 각 행을
www.acmicpc.net
문제
내 풀이 -시간초과-
# BOJ 2573 - 빙산 - 시간초과
import sys
sys.setrecursionlimit(100000)
input = sys.stdin.readline
# 상 우 하 좌
dr = [-1, 0, 1, 0]
dc = [0, 1, 0, -1]
def dfs_count(r, c):
for m in range(4):
nr = r + dr[m]
nc = c + dc[m]
if (0 <= nr < row) and (0 <= nc < col) and visit[nr][nc] == False and sea[nr][nc] != 0:
visit[nr][nc] = True
dfs_count(nr, nc)
def dfs_melt(r, c):
count = 0
height = sea[r][c]
# 인접한 바다 수 세기
for m in range(4):
nr = r + dr[m]
nc = c + dc[m]
if (0 <= nr < row) and (0 <= nc < col) and sea[nr][nc] == 0 and land[nr][nc] == False:
count += 1
# 업데이트
ini = height - count
if ini > 0:
sea[r][c] = height - count
else:
sea[r][c] = 0
# 입력
row, col = map(int, input().split())
sea = [list(map(int, input().split())) for _ in range(row)]
year = 0
while True:
year += 1
# 매해 방문 초기화
visit = [[False]*col for _ in range(row)]
# 빙산 덩이 개수 카운팅
iceberg = 0
for i in range(row):
for j in range(col):
if sea[i][j] != 0:
if not visit[i][j]:
iceberg += 1
visit[i][j] = True
dfs_count(i, j)
# 덩이가 2개 이상일 경우
if iceberg > 1:
print(year-1)
exit()
# 빙산 녹이기
land = [[False]*col for _ in range(row)]
for i in range(row):
for j in range(col):
if sea[i][j] != 0:
land[i][j] = True
dfs_melt(i, j)
# 다 확인 하는지 체크
check = 0
for i in range(row):
if any(sea[i]) == False:
check += 1
if check == row:
print('0')
exit()
해설
로직은 맞는거 같다. 하지만 시간초과로 실패. 답을 보고 내 답을 개선해봤다.
문제는 시간복잡도를 제외하고는 단순 구현에 가깝다. 이번에도 느끼지만 dfs 재귀 방식은 파이썬으로는 너무 느리다.
정답 풀이
# BOJ 2573 - 빙산
from collections import deque
import copy
import sys
input = sys.stdin.readline
# 상 우 하 좌
dr = [-1, 0, 1, 0]
dc = [0, 1, 0, -1]
# bfs 알고리즘으로 덩어리 개수 탐색
def bfs_count(i, j):
q = deque()
q.append([i, j])
visit = [[0] * col for i in range(row)]
visit[i][j] = 1
while q:
a, b = q.popleft()
for k in range(4):
nr = a + dr[k]
nc = b + dc[k]
if 0 <= nr < row and 0 <= nc < col and visit[nr][nc] == 0 and temp[nr][nc] != 0:
temp[nr][nc] = 0
visit[nr][nc] = 1
q.append([nr, nc])
# dfs에 유사하게 주면 바다(0) 개수를 세고 리턴
def dfs_melt(r, c):
count = 0
# 인접한 바다 수 세기
for m in range(4):
nr = r + dr[m]
nc = c + dc[m]
if (0 <= nr < row) and (0 <= nc < col) and ts[nr][nc] == 0:
count += 1
return count
# 모두다 바다가 됬는지 체크하는 함수
def checkz():
for i in range(row):
for j in range(col):
if sea[i][j] != 0:
return False
# 전부 0일 경우
return True
# 입력
row, col = map(int, input().split())
sea = [list(map(int, input().split())) for _ in range(row)]
year = 1
while True:
# 다 녹였는지 체크
if checkz():
print(0)
break
# 빙산 녹이기
ts = copy.deepcopy(sea)
for i in range(row):
for j in range(col):
if ts[i][j] != 0:
temp = sea[i][j] - dfs_melt(i, j)
sea[i][j] = temp if temp >= 0 else 0
# 빙산 덩이 개수 카운팅
temp = copy.deepcopy(sea)
iceberg = 0
for i in range(row):
for j in range(col):
if sea[i][j] != 0:
if temp[i][j] != 0:
temp[i][j] = 0
bfs_count(i, j)
iceberg += 1
# 빙산 덩어리의 개수 체크
if iceberg > 1:
print(year)
break
year += 1
출처:https://pacific-ocean.tistory.com/352
해석
실제로 로직은 거의 동일하다. 다만 copy 함수가 등장했는데 이게 시간 단축에 큰 의미가 있어보인다. 파악해보자.
'sw사관학교 정글 2기 > 03 DFS, BFS, 위상정렬' 카테고리의 다른 글
[BFS] 백준 숨바꼭질 1697번 with Python3 (0) | 2021.08.24 |
---|---|
[위상정렬] 백준 장난감 찾기 2637번 with Python3 ★★ (0) | 2021.08.24 |
[DFS] 백준 구슬 찾기 2617번 with Python3 (0) | 2021.08.23 |
[DP, BFS] 백준 2294번 동전 2 with Python3 (0) | 2021.08.21 |
[BFS] 백준 3055번 탈출 with Python3 (0) | 2021.08.21 |
댓글