관련 링크 : https://www.acmicpc.net/problem/1103

백준 1103 : 게임

형택이는 1부터 9까지의 숫자와, 구멍이 있는 직사각형 보드에서 재밌는 게임을 한다. 일단 보드의 가장 왼쪽 위에 동전을 하나 올려놓는다. 그다음에 다음과 같이 동전을 움직인다.

  1. 동전이 있는 곳에 쓰여 있는 숫자 X를 본다.
  2. 위, 아래, 왼쪽, 오른쪽 방향 중에 한가지를 고른다.
  3. 동전을 위에서 고른 방향으로 X만큼 움직인다. 이때, 중간에 있는 구멍은 무시한다. 만약 동전이 구멍에 빠지거나, 보드의 바깥으로 나간다면 게임은 종료된다. 형택이는 이 재밌는 게임을 되도록이면 오래 하고 싶다. 보드의 상태가 주어졌을 때, 형택이가 최대 몇 번 동전을 움직일 수 있는지 구하는 프로그램을 작성하시오.

입력

줄에 보드의 세로 크기 N과 가로 크기 M이 주어진다. 이 값은 모두 50보다 작거나 같은 자연수이다. 둘째 줄부터 N개의 줄에 보드의 상태가 주어진다. 쓰여 있는 숫자는 1부터 9까지의 자연수 또는 H이다. 가장 왼쪽 위칸은 H가 아니다. H는 구멍이다.

1
2
3
4
3 7
3942178
1234567
9123532
1
2
3
4
3 7
2H9HH11
HHHHH11
9HHHH11

출력

첫째 줄에 문제의 정답을 출력한다. 만약 형택이가 동전을 무한번 움직일 수 있다면 -1을 출력한다.

1
5
1
2

풀이

처음에 이전에 배운 DFS로 풀었다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
import sys

sys.setrecursionlimit(10000) # Recursive Depth 늘려줌

N, M = map(int, input().strip().split())
board = [
    list(map(lambda x: int(x) if x.isnumeric() else x, input().strip())) 
    for _ in range(N)]
history = [] # 무한 루프 방지를 위해 이전 경로 기억

def dfs(count, i, j):
    if [i, j] in history:
        return -1
    else:
        if 0<= i < N and 0<= j < M and board[i][j] != 'H': 
         	#밖이나 구멍으로 떨어지지 않은 경우
            move = board[i][j]
            res = []
            for idx in [[i+move, j], [i-move, j], [i, j+move], [i, j-move]]: #상하좌우
                history.append([i, j])
                res.append(dfs(count+1, *idx))
                history.pop()
            if -1 in res:
                return -1
            else:
                return max(res)
        else:
            return count

print(dfs(0, 0, 0))

근데 무슨 짓을 해도 시간초과라 구글링 해보니 Dynamic Programming을 해야한다더라. 그래서 관련 글들 찾아보고 Memoization를 사용해서 풀었다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
import sys

sys.setrecursionlimit(10000)

input = sys.stdin.readline
N, M = map(int, input().strip().split())
board = [
    list(map(lambda x: int(x) if x.isnumeric() else x, input().strip())) 
    for _ in range(N)]
memo = [[-1] * M for _ in range(N)]  # dp를 위한 Memoization
history = [] 

def dfs(count, i, j):
    if [i, j] in history:
        memo[i][j] = "inf"
    else:
        if (
            0 <= i < N
            and 0 <= j < M
            and board[i][j] != "H"
            and memo[i][j] != "inf" #무한 루프가 발견되면 더 할 필요 없음
            and count > memo[i][j]
        ):
            memo[i][j] = count
            move = board[i][j]
            for idx in [[i + move, j], [i - move, j], [i, j + move], [i, j - move]]:
                history.append([i, j])
                dfs(count + 1, *idx)
                history.pop()

dfs(0, 0, 0)

# 결과 출력
flat = [col for row in memo for col in row]
if "inf" in flat:
    print(-1)
else:
    print(max(flat) + 1)

Leave a comment