ps | |
---|---|
링크 | programmers.co.kr/… |
출처 | 프로그래머스 |
문제 번호 | 72415 |
문제명 | 카드 짝 맞추기 |
레벨 | Level 3 |
분류 |
구현, BFS, DP |
시간복잡도 | O(n^2 * 2^n) |
인풋사이즈 | n<=6 |
사용한 언어 | Python |
해결날짜 | 2021/01/29 |
출처 |
ps:problems:programmers:2021_kakao_blind_recruitment |
"""Solution code for "Programmers 72415. 카드 짝 맞추기".
- Problem link: https://programmers.co.kr/learn/courses/30/lessons/72415
- Solution link: http://www.teferi.net/ps/problems/programmers/72415
"""
import collections
import functools
INF = float('inf')
def solution(board, r, c):
def next_pos(pos, cards):
r, c = pos
for dr, dc in ((1, 0), (-1, 0), (0, 1), (0, -1)):
nr, nc = r + dr, c + dc
if 0 <= nr < 4 and 0 <= nc < 4:
yield nr, nc
for i in range(1, 5):
nr, nc = r + dr * i, c + dc * i
if not (0 <= nr < 4 and 0 <= nc < 4):
yield nr - dr, nc - dc
break
elif board[nr][nc] in cards:
yield nr, nc
break
@functools.lru_cache(maxsize=None)
def bfs(start, target, cards):
if start == target:
return 0
visited = set()
queue = collections.deque([(start, 0)])
while queue:
cur, dist = queue.popleft()
for next_ in next_pos(cur, cards):
if next_ == target:
return dist + 1
if next_ not in visited:
visited.add(next_)
queue.append((next_, dist + 1))
return INF
@functools.lru_cache(maxsize=None)
def min_dist_rec(cur_pos, cards):
if not cards:
return 0
min_dist = INF
for card_to_clear in cards:
pos1, pos2 = pos[card_to_clear]
next_cards = tuple(card for card in cards if card != card_to_clear)
dist1 = (bfs(cur_pos, pos2, cards) + bfs(pos2, pos1, cards) +
min_dist_rec(pos1, next_cards))
dist2 = (bfs(cur_pos, pos1, cards) + bfs(pos1, pos2, cards) +
min_dist_rec(pos2, next_cards))
min_dist = min(min_dist, dist1, dist2)
return min_dist
pos = collections.defaultdict(list)
for r_, row in enumerate(board):
for c_, card in enumerate(row):
if card != 0:
pos[card].append((r_, c_))
cards = tuple(pos)
return len(cards) * 2 + min_dist_rec((r, c), cards)