[백준] 2098 외판원 순회

dmddo1222·2022년 4월 24일
0

algorithm

목록 보기
4/5

2098 외판원순회

비트마스킹을 활용한 동적계획법.
제한조건으로 순회 노드수 N이 2 <= N <= 16 이므로 dp table을 아래와 같이 정의할 때 O((2^N)(N^2))로 풀 수 있다.

순회의 특성상 어느 노드에서 시작해도 최소 비용을 결정하는 순회경로는 변하지 않을 것이다. 따라서 집합 S, 노드 i에 대해

dp[S][i]=0번에서 시작해서 S의 모든 정점을 순회한 후 정점 i에 도착할 때의 최소 비용\displaystyle dp[S][i] \displaystyle \displaystyle= 0번에서\space 시작해서 \space S의\space모든\space 정점을\space 순회한\space 후\space 정점\space i에\space 도착할\space 때의\space 최소\space 비용

라고 하면,

dp[S][i]=minjS(dp[S{j}][j]+W[j][i])dp[S][i]= min_{j\in S} \left ( dp[S-\{j\}][j]+W[j][i] \right)

가 성립하고

dp[{0,1,2,...,N1}][0]dp[\{0, 1, 2, ..., N-1\}][0]

이 구하고자 하는 값이 된다.

부분집합을 구현하는 과정에서 비트마스킹을 사용하게 된다.
부분집합 S를 S의 각 원소가 1인 길이 N인 이진수로 표현한다면
i가 S의 원소라는 것은 S의 번째 비트가 1이라는 것이고, 이것은 S & (1<<i) == 1 또는 (S>>i) & 1 == 1로 확인 할 수 있다.
S의 원소 i를 S에서 제외하는 것은

S{i}=S{i}cS-\{i\} = S \cap\{i\}^{c}

이므로 S & ~(1<<i)이다.

python code

import sys

N = int(sys.stdin.readline())
W = [list(map(int, sys.stdin.readline().split())) for _ in range(N)]
for i in range(N):
    for j in range(N):
        if W[i][j] == 0:
            W[i][j] = 1e9

dp = [[1e9]*N for _ in range(1<<N)]
dp[0][0] = 0
for S in range(1<<N):
    for i in range(N):
        for j in range(N):
            if S & (1<<j):
                dp[S][i] = min(dp[S][i], dp[S&(~(1<<j))][j] + W[j][i])

print(dp[-1][0])

0개의 댓글

관련 채용 정보