반응형
https://www.acmicpc.net/problem/1029
1029번: 그림 교환
첫째 줄에 예술가의 수 N이 주어진다. N은 2보다 크거나 같고, 15보다 작거나 같은 자연수이다. 둘째 줄부터 N개의 줄에는 N개의 수가 주어진다. i번째 줄의 j번째 수는 j번 예술가가 i번 예술가에
www.acmicpc.net
사실 이전 포스팅에서 풀었던 외판원 순회 문제 를 찾아 풀어 보며 비트마스크를 이용한 메모제이션을
공부한 것이 본 문제에서 막혔기 때문이다!
해결 방법 : DP 메모제이션
- 메모제이션을 적용하기 위해 외판원 순회 문제에서 사용한 비트마스크에 하나의 차원을 추가해 주어야한다.
- 같은 node 시점에서 같은 path로 구성되어 있다고 해도, 현재 그림의 가격에 따라 다음으로 그림을 구매할 artist가 바뀌기 때문이다.
- 따라서 메모제이션은 [현재 artist][현재까지 구입한 artist path][현재 그림 price]의 3차원 배열에 적용된다.
본 문제는 완전 탐색으로는 시간 초과가 발생하여, 메모제이션을 적용해야만 한다.
하지만, 메모제이션으로 시간 단축이 가능한 이유는 그림 가격이 0~9로 좁은 범위를 가지기 때문이다.
솔직히 더 많은 알고리즘 기법을 억지로 적용하게 만든 느낌이다.
(기본 외판원 순회 문제의 경우, 메모제이션 적용으로 인한 탐색 횟수 감소가 확연하다.)
import sys
input = sys.stdin.readline
def solution(n, arr):
M = [[[0] * 10 for j in range(1 << n)] for i in range(n)] # M[artist][path(bin)][price]
def dfs(artist, path, price):
if M[artist][path][price] != 0: # 메모제이션 적용
return M[artist][path][price]
count = 0 # 현재 artist 부터의 최대 거래 횟수
for nextA in range(1, n):
if arr[artist][nextA] < price or path & (1 << nextA) > 0:
continue
count = max(count, 1 + dfs(nextA, path | (1 << nextA), arr[artist][nextA]))
M[artist][path][price] = count # 메모!
return count
return 1 + dfs(0, 1, 0)
if __name__ == '__main__':
n = int(input())
arr = []
for i in range(n):
arr.append([int(j) for j in input().strip()])
result = solution(n, arr)
print(result)반응형
'IT study > 알고리즘 문제 풀이' 카테고리의 다른 글
| 백준 1019 : 책 페이지 (0) | 2021.05.18 |
|---|---|
| 백준 1016 : 제곱ㄴㄴ수 (0) | 2021.05.17 |
| 백준 2098 : 외판원 순회 (0) | 2021.05.16 |
| 백준 2579 : 계단 오르기 (0) | 2021.05.13 |
| 백준 11727 : 2 * n 타일링 2 (feat. 11726 : 2 * n 타일링) (0) | 2021.05.13 |