Skip to content
This repository was archived by the owner on Mar 18, 2024. It is now read-only.

[2023-08-16] wooyeol #112 #127

Merged
merged 2 commits into from
Aug 22, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
99 changes: 99 additions & 0 deletions BOJ/빙산/wooyeol.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
"""
빙산
https://www.acmicpc.net/problem/2573

풀이시간
10:33 ~ 14:12 (풀이 실패) + 4시간 (풀이 성공)

접근법
무슨 알고리즘으로 풀이 할 수 있을까? BFS

시간 초과와 메모리 초과로 실패했습니다. -> 리뷰를 보며 다시 풀이를 진행하여 풀이해낼 수 있었습니다.

- 빙산 테이블을 만들면서 빙산의 위치를 덱에 기억시켜놓고 첫 요소를 기점으로 BFS로 진행합니다.
- BFS 연산을 거치며 해당 빙산 주변 바다의 갯수를 통해 빙산의 높이를 조절합니다.
- 하나의 빙산 덩어리는 첫 요소를 기점으로 BFS를 진행하였을 때 모든 요소를 탐색 할 수 있습니다.
- 혹시라도 빙산의 위치를 저장시킨 덱의 요소를 다 검사하였을 때 한 번 더 BFS 탐색을 한다면 두 개의 빙산 덩어리가 발생하였다는 것 이므로 현재 연도를 반환
- 만약 BFS 연산이 일어나지 않았다면 0개의 덩어리라는 것이므로 0을 반환
"""

import sys
from collections import deque

input = sys.stdin.readline

R, C = map(int, input().split())

iceberg_queue: deque = deque()
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

iceberg_queue라는 작업 큐를 두신 게 굉장히 좋은 것 같아요! 저는 set 자료형으로 매번 copy를 했었는데 copy해서 메모리가 계속 쌓이는 것보다 이 방식이 더 좋아보입니다 👍👍 고생하셨어요 우열님~!!!


iceberg: list = list()

# 빙산 데이터 입력 받기
for r in range(R):
data = list(map(int, input().split()))
checksum = sum(data)
# 빙산의 높이 값이 존재한다면
if checksum > 0:
for c in range(C):
# 작업 큐 업데이트 (year, row, col)
if data[c] != 0:
iceberg_queue.append((0, r, c))
iceberg.append(data)


def bfs(x: int, y: int):
q: deque = deque([(x, y)])
visited[x][y] = True

directions = ((1, 0), (-1, 0), (0, 1), (0, -1))

while q:
x, y = q.popleft()

# 4방향으로 탐색
for dx, dy in directions:
nx, ny = x + dx, y + dy

# 방문 빙산인지 확인
if (0 <= nx < R) and (0 <= ny < C) and not visited[nx][ny]:
# 주변에 바다가 있는지 확인하고 해당 칸이 바다인지도 확인
if iceberg[nx][ny] == 0 and iceberg[x][y] != 0:
iceberg[x][y] -= 1

# 주변에 바다가 아닌 빙산이 있다면 다음 탐색을 위해 큐에 삽입
if iceberg[nx][ny] != 0:
visited[nx][ny] = True
q.append((nx, ny))

# 4방향으로 바다를 검사했음에도 빙산이 녹지 않았다면 빙산 덱에 추가
if iceberg[x][y] != 0:
iceberg_queue.append((current_year + 1, x, y))

return 1


current_year = 0
while True:
cnt = 0
visited = [[False] * C for _ in range(R)]

# print(f"\niceberg queue : {iceberg_queue}")
# print(f"current_year : {current_year}\n")
# for row in iceberg:
# print(*row)

while iceberg_queue and iceberg_queue[0][0] == current_year:
y, r, c = iceberg_queue.popleft()
if iceberg[r][c] and not visited[r][c]:
cnt += bfs(r, c)

# 빙산 덩어리 갯수가 2개 이상이 된다면 종료
if cnt > 1:
print(current_year)
break
# 빙산 덩어리가 0개가 된다면 종료
elif cnt == 0:
print(0)
break
# 빙산 덩어리가 1개라면 다시 다음해로 이동
current_year += 1
110 changes: 110 additions & 0 deletions BOJ/빙산/wooyeol2.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
# 메모리 초과로 인하여 실패나는 코드

import sys
from collections import deque

input = sys.stdin.readline


def check_cycle(R: int, C: int, start_point: tuple, iceberg_count: int, iceberg: list):
directions = ((1, 0), (-1, 0), (0, 1), (0, -1))
count: int = 1
visited = [[False] * C for _ in range(R)]
s_queue = deque([start_point])

while s_queue:
tx, ty = s_queue.popleft()
visited[tx][ty] = True
for dtx, dty in directions:
ntx, nty = tx + dtx, ty + dty

# 범위 검증
if 0 <= ntx < R and 0 <= nty < C:
if not visited[ntx][nty] and iceberg[ntx][nty]:
s_queue.append((ntx, nty))
count += 1

# 하나의 점으로부터 bfs 탐색을 했을 때 모든 점이 카운트 되지 않았다면 2개 이상의 cycle이 생긴 것으로 확인
if iceberg_count != count:
return True
return False


def solution(R: int, C: int, iceberg: list, queue: deque):
iceberg_count = len(queue)

pre_year: int = 0

directions = ((1, 0), (-1, 0), (0, 1), (0, -1))

record_iceberg: list = [item[:] for item in iceberg]

while queue:
year, x, y = queue.popleft()

if year > pre_year:
iceberg = [item[:] for item in record_iceberg]
start_point = (x, y)

# 2개 이상의 덩어리가 생겼는지 확인
if check_cycle(R, C, start_point, iceberg_count, iceberg):
return year + 1

# 4방향으로 탐색하며 빙산 값 업데이트
temp_count = 0
for dx, dy in directions:
nx, ny = x + dx, y + dy

# 범위 검증
if 0 <= nx < R and 0 <= ny < C:
# 0이라면
if iceberg[nx][ny] == 0:
# 낮아지는 빙하 갯수 카운트
temp_count += 1

# 업데이트 된 빙산 높이 업데이트
record_iceberg[x][y] = max(0, iceberg[x][y] - temp_count)

# 작업 큐 업데이트
if record_iceberg[x][y]:
queue.append(((year + 1), x, y))
else:
iceberg_count -= 1

pre_year = year

# print()
# print(queue)
# for tr in iceberg:
# print(*tr)
# print()
# for tf in record_iceberg:
# print(*tf)
# print()

return 0


def main():
R, C = map(int, input().split())

queue: deque = deque()

iceberg: list = list()

# 빙산 데이터 입력 받기
for r in range(R):
data = list(map(int, input().split()))
checksum = sum(data)
# 빙산의 높이 값이 존재한다면
if checksum > 0:
for c in range(C):
# 작업 큐 업데이트 (year, row, col)
if data[c] != 0:
queue.append((0, r, c))
iceberg.append(data)

return solution(R, C, iceberg, queue)


print(main())