풀이
실패 → 시간 초과
def safe(h): # h: 가준 물 높이 / que = deque()
# 부분 1
que = deque()
visited = [[0 for _ in range(N)] for _ in range(N)]
# 부분 2
while True:
nextSafe = findNextSafe(h,visited)
if nextSafe:
visited[nextSafe[0]][nextSafe[1]] = 1
que.append(nextSafe)
else: return
# 부분 3
while que:
node = que.popleft()
x = node[0]
y = node[1]
for i in a:
nx = x+i[0]
ny = y+i[1]
if 0<=nx<N and 0<=ny<N and visited[nx][ny] == 0 and lst[nx][ny] > h:
visited[nx][ny] = 1
que.append((nx,ny))
def findNextSafe(h, visited):
for i in range(0, N):
for j in range(0, N):
if visited[i][j] == 0 and lst[i][j] > h:
waterCnt[h] += 1
return (i, j)
return None
input = __import__('sys').stdin.readline
N = int(input())
a = [[-1, 0], [1, 0], [0, -1], [0, 1]]
lst = [list(map(int, input().split(" "))) for _ in range(N)]
waterCnt = [-1]*101
# 물 높이
waterCnt[0] = 1
waterCnt[100] = 0
for i in range(N):
for j in range(N):
h = lst[i][j]
if waterCnt[h] == -1:
waterCnt[h] += 1
safe(h)
safe(100)
print(max(waterCnt))-
용어
- 안전한 땅: 특정 물높이
h에 대해h를 초과하는 지역 - 안전지대: 연결되어있는 안전한 땅을 안전지대라고 부름 (연결된 것중 최대 크기)
- 안전한 땅: 특정 물높이
-
전역변수
waterCnt배열: 각 물높이에 대해 안전지대가 몇 개인지 개수를 저장a배열: 연결된 다음 안전지대를 찾을 때, 좌표 이동을 위한 배열lst배열: 땅 높이에 대한 정보가 저장
-
findNextSafe(h, visited)의 역할: 안전한 땅을 탐색하다가 길이 끊겼을 경우(혹은 최초에), 다음으로 아직 방문하지 않은 안전한 땅을 찾는 역할- 배열 전체 (땅 전체)를 순회하면서, 아직 방문하지 않았고, 안전한 땅을 찾으면, 해당 땅 위치를
return- 또한 이 경우 새로운 안전한 땅 유닛 (=안전지대)의 시작이기 때문에, 해당 높이의 안전지대 count를 올려줌 (
waterCnt[h]) - 찾는 값이 없을 경우
None을return
- 또한 이 경우 새로운 안전한 땅 유닛 (=안전지대)의 시작이기 때문에, 해당 높이의 안전지대 count를 올려줌 (
- 배열 전체 (땅 전체)를 순회하면서, 아직 방문하지 않았고, 안전한 땅을 찾으면, 해당 땅 위치를
-
safe(h)의 역할: 특정 물높이h에 대해h를 초과하는 지역(=안전한 땅)을 방문하고 그 지역과 연결된 다른 안전한 땅을 차례로 방문하는 함수- 부분 1:
visited배열: 해당 물높이h에 대해서 탐색할 때, 특정 지역에 방문 했는지를 체크하는 용도의 배열que: 선입 선출의 특징을 가진 리스트로, 갈 수 있는 땅을 발견했을 때, 해당que에 집어 넣음. 또한 순서대로 빼면서, 빼낸 땅에 대해 인접한 안전한 땅이 또 있는지 확인하기 위해 선언
- 부분 2
findNextSafe함수를 통해 다음 안전지대 시작점을 찾을 수 없을 때까지 계속 안전지대 탐색을 반복
- 부분 3
- 방문한 땅을 하나 빼냄 →
node = que.popleft() - 해당 땅에 인접한 땅들을 순회(
(x-1, y),(x+1, y),(x, y-1),(x, y+1)) - 그 땅이 배열의 안에 있고(
0<=nx<N and 0<=ny<N), 안전한 땅이며(lst[nx][ny] > h), 아직 방문하지 않은 곳(visited[nx][ny] == 0)인지를 체크 - 모두
True라면 해당 땅을 방문하고, 다음 탐색을 위해que에 삽입 - 이것을
que가 다 빌 때까지 반복
- 방문한 땅을 하나 빼냄 →
- 부분 1:
-
물 높이(
h) 관련h= 0일 때, 안전지대는 1개 → 모든 땅이 물에 잠기지 않았음h= 100 일때, 안전지대는 0개 → 모든 땅이 물에 잠겼음- 이 외에 물높이에 따라 안전지대의 개수가 변하기 위해서는, 물높이가 특정 땅의 높이와 일치되어야한다.
- 즉, 땅 높이가 1 5 8일 때, 물높이 1에서 부터 4까지는 동일한 땅이 물에 잠기고 동일한 땅이 물위에 있지만, 5부터는 물에 잠긴 모습이 변하게 됨.
- 따라서, 탐색에 적용할
h의 값은 모든 땅의 높이와 최소 높이 0, 최고 높이 100이다.
-
출력:
waterCnt의 최대값을 출력 -
시간 초과 원인:
- 다음 안전지대 시작 위치를 찾는걸 어떻게 해야하지 헷갈렸는데, 어김없이 거기서 문제가 생김
findNextSafe함수에서 다음 안전지대 시작점을 찾을 때, 매번 처음부터 끝까지 탐색을 하니까 시간이 오래걸림- 함수
findNextSafe와safe로 나누지 말고 2중 포문 돌리면서 다음 시작위치를 탐색하다가 시작위치를 찾으면que에 넣어서 안전지대 하나 탐험 시작. - 그리고 탐험 끝나면, 아까 찾은 안전지대 시작위치 뒤부터 탐색을 시작해서 다음 안전지대를 찾는 방식으로 수정
성공
from collections import deque
def safe(h): # h: 가준 물 높이 / que = deque()
visited = [[0 for _ in range(N)] for _ in range(N)]
for i in range(0, N):
for j in range(0, N):
if visited[i][j] == 0 and lst[i][j] > h:
waterCnt[h] += 1
visited[i][j] = 1
que.append((i,j))
while que:
node = que.popleft()
x = node[0]
y = node[1]
for a in A:
nx = x+a[0]
ny = y+a[1]
if 0<=nx<N and 0<=ny<N and visited[nx][ny] == 0 and lst[nx][ny] > h:
visited[nx][ny] = 1
que.append((nx,ny))
input = __import__('sys').stdin.readline
N = int(input())
A = [[-1, 0], [1, 0], [0, -1], [0, 1]]
lst = [list(map(int, input().split(" "))) for _ in range(N)]
waterCnt = [-1]*101
waterCnt[0] = 1
waterCnt[100] = 0
for i in range(N):
for j in range(N):
h = lst[i][j]
if waterCnt[h] == -1:
waterCnt[h] += 1
safe(h)
safe(100)
print(max(waterCnt))Computer #PS