Notice
Recent Posts
Recent Comments
Link
«   2026/06   »
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
Archives
Today
Total
관리 메뉴

dh-winternagi 님의 블로그

(1311) 할 일 정하기 1 본문

백준 (C++)/Solve

(1311) 할 일 정하기 1

dh-winternagi 2026. 4. 22. 19:46

https://www.acmicpc.net/problem/1311

단계별로 풀어보기

40단계(동적 계획법 3) 2번째

 

 

 

비스마스크를 이용한 DP문제다

dp[state]는 state 상태에서 남은 일을 추가로 하기 위한 비용의 최소값이다. state에서 n번째 비트는 n번 일을 의미하며 비트값이 1이면 한 일, 0이면 아직 하지 않은 일을 의미한다.

state 상태에서 i번 사람이 j번 일을 추가로 하면 d[i][j]가 추가되므로 dp[state]와 dp[state|(1<<j)]+d[i][j]를 비교해 값을 갱신해주고, i를 1부터 N까지 순회하며 진행하면 된다.

 

비스마스크를 이용한 DP는 재귀와 DP에 대해 잘 알아야 하는 굉장히 어려운 파트이다.

처음 배울 땐 이해 못했는데 나중에 실력이 쌓이고 Digit DP라는 것에 대해 배울 때 비트마스크 DP에 대해서도 이해하게 되었는데 설명하기가 굉장히 어렵다. 본인이 코드나 갱신 과정을 분석하면서 이해하는 것이 최선이다.

 

 

 

#include <iostream>
#include <vector>
using namespace std;
#define INF 200001

int main() {
  ios_base::sync_with_stdio(false);
  cin.tie(NULL);
  cout.tie(NULL);
  
  int n;
  
  cin >> n;
  
  vector d(n, vector<int> (n));
  vector<int> dp(1<<n, -1);
  
  for(int i=0;i<n;i++){
    for(int j=0;j<n;j++){
      cin >> d[i][j];
    }
  }
  
  auto func= [&](auto self, int now, int state) -> int {
    if(now==n)  return 0;
    
    int &ret= dp[state];
    
    if(ret!=-1)  return ret;
    
    ret= INF;
    
    for(int i=0;i<n;i++){
      if(state&(1<<i))  continue;
      
      ret= min(ret, self(self, now+1, state|(1<<i))+d[now][i]);
    }
    
    return ret;
  };
  
  cout << func(func, 0, 0);
  
  return 0;
}

'백준 (C++) > Solve' 카테고리의 다른 글

(1086) 박성원  (0) 2026.04.22
(2098) 외판원 순회  (0) 2026.04.22
(11723) 집합  (0) 2026.04.22
(1069) 집으로  (0) 2026.04.22
(7869) 두 원  (0) 2026.04.22