Don't Go Show의 흔적들..
테트로미노 문제에서 가장 골치 아픈것은 바로 T자이다.
대부분의 도형은 DFS를 통해 구현이 가능하지만, T자만큼은 구현이 불가능하기 때문이다.
T자를 구현하기 위해서는 DFS를 돌 때, 현재 위치를 가리키는 커서를 움직이지 않도록 해야한다
import sys
input = sys.stdin.readline
dx = [-1, 0, 1, 0]
dy = [0, 1, 0, -1]
answer = -1
def DFS(L, x, y, total):
global answer
if L == 4:
answer = max(answer, total)
else:
for k in range(4):
xx = x + dx[k]
yy = y + dy[k]
if 0<=xx<N and 0<=yy<M and ch[xx][yy] == 0:
ch[xx][yy] = 1
DFS(L+1, xx, yy, total+board[xx][yy])
DFS(L+1, x, y, total+board[xx][yy])
ch[xx][yy] = 0
if __name__=="__main__":
N, M = map(int,input().split())
board = [list(map(int,input().split())) for _ in range(N)]
ch = [[0]*M for _ in range(N)]
for i in range(0, N):
for j in range(0, M):
ch[i][j] = 1
DFS(1, i, j, board[i][j])
ch[i][j] = 0
print(answer)
import sys
input = sys.stdin.readline
dx = [-1, 0, 1, 0]
dy = [0, 1, 0, -1]
answer = -1
def solution(x, y):
def DFS(L, x, y, total):
global answer
if L == 4:
answer = max(answer, total)
else:
for k in range(1,4): # 변경점 2
xx = x + dx[k]
yy = y + dy[k]
if 0 <= xx < N and 0 <= yy < M and ch[xx][yy] == 0:
ch[xx][yy] = 1
DFS(L+1, xx, yy, total+board[xx][yy])
ch[xx][yy] = 0
def t_shape(L, x, y, total): # 변경점 1
global answer
if L == 4:
answer = max(answer, total)
else:
for k in range(4):
xx = x + dx[k]
yy = y + dy[k]
if 0 <= xx < N and 0 <= yy < M and ch[xx][yy] == 0:
ch[xx][yy] = 1
t_shape(L+1, x, y, total+board[xx][yy])
ch[xx][yy] = 0
def box_shape(x, y, total): # 변경점 2
global answer
xx = x + 1
yy = y + 1
if 0<=xx<N and 0<=yy<M:
answer = max(answer, total+board[xx][yy]+board[xx-1][yy]+board[xx][yy-1])
ch[x][y] = 1
DFS(1, x, y, board[x][y])
t_shape(1, x, y, board[x][y])
box_shape(x, y, board[x][y])
ch[x][y] = 0
if __name__ == "__main__":
N, M = map(int, input().split())
board = [list(map(int, input().split())) for _ in range(N)]
ch = [[0]*M for _ in range(N)]
for i in range(0, N):
for j in range(0, M):
solution(i, j)
print(answer)
T자 도형을 탐색하는 함수를 따로 만들어서 board[i][j]
마다 한번씩만 T자 도형의 최대값을 구하도록 했다.
T자 도형을 탐색하는 방법은 맨위 그림에서 커서를 고정한 상태로 주변을 탐색하는 방법을 사용했다.
그럼에도 불구하고 시간초과가 발생해서 이번에는 박스 모양의 도형도 별도의 함수로 뺐다.
박스 모양 도형을 빼면 DFS를 탐색할 때 4방향 모두를 탐색할 필요가 없기 때문이다.
박스 모양 도형의 최대값을 구하는 함수를 작성한 뒤, 기존 DFS에서 3방향만 탐색하도록 했다.
DFS에서 시간복잡도를 줄이는 가장 좋은 방법은 가지치기이다.
위 풀이는 이러한 점을 고려하지 못했다.
import sys
input = sys.stdin.readline
dx = [-1, 0, 1, 0]
dy = [0, 1, 0, -1]
answer = -1
def DFS(L, x, y, total):
global answer
if L == 4:
answer = max(answer, total)
elif (total+max_value*(4-L)) <= answer: # 변경점2
return
else:
for k in range(4):
xx = x + dx[k]
yy = y + dy[k]
if 0 <= xx < N and 0 <= yy < M and ch[xx][yy] == 0:
ch[xx][yy] = 1
if L == 2: # 변경점 1
DFS(L+1, x, y, total+board[xx][yy])
DFS(L+1, xx, yy, total+board[xx][yy])
ch[xx][yy] = 0
if __name__ == "__main__":
N, M = map(int, input().split())
board = [list(map(int, input().split())) for _ in range(N)]
ch = [[0]*M for _ in range(N)]
max_value = max(map(max, board)) # 변경점2
for i in range(0, N):
for j in range(0, M):
ch[i][j] = 1
DFS(1, i, j, board[i][j])
ch[i][j] = 0
print(answer)
위 그림에서 L=2일 때, 한번만 커서를 고정시켜도 T자 도형을 탐색할 수 있다.
즉, 별도로 함수를 만들 필요 없이 조건문을 이용해서 L=2일 때만 커서를 움직이지 않는 DFS를 돌게한다면 T자 도형 탐색이 가능하다.
가지치기는 DFS에서 시간 단축의 가장 중요한 요소이다
전체 배열에서 수의 최대값을 저장한 max_value
변수를 추가했다.
그리고 L번째 방문에서 남은 4-L 번의 방문을 모두 max_value
로 한다고 해도 answer보다 크지 않다면 answer는 갱신되지 않을 것이고, 이는 더 이상 나머지 블록을 방문할 필요가 없다는 뜻이다.
if (total+max_value*(4-L)) <= answer:
이 조건문을 통해 더 이상 방문을 해도 최대값을 갱신할 가망이 없을 때 그대로 return 해버리는 가지치기를 추가했다.