끄적끄적 코딩
article thumbnail

비트마스크, 다이나믹프로그래밍 문제입니다.

최소의 비용으로 모든 도시를 들려서 처음 출발한 도시로 도착하는 문제입니다.

다음의 비용은 동일합니다.

A -> B -> C -> D -> A
B -> C -> D -> A -> B
C -> D -> A -> B -> C
D -> A -> B -> C -> D

각각의 도시를 들렀을 때 최소값을 저장해가면서(DP) 최소비용을 찾습니다.
이 때 해당 도시를 들렸는지 확인하는 과정에서 비트마스크를 사용합니다. 

cost[x][y]에서 x는 현재위치, y는 방문한 도시들을 담고있습니다.
cost[3][15]는 현재 위치는 3이고 1, 2, 3, 4의 도시를 방문한 상태입니다.
(15 = 1 + 2 + 4 + 8)


1. 모든 도시를 방문했는지 확인
1-true. 시작점으로 돌아갈 수 있는지 확인
1-true-true. 시작점으로 돌아가는 비용 반환
1-true-false. INF값 반환
1-false. 2로 이동

2. 현재 위치 이미 계산했는지 확인
2-true. 계산된 값 반환
2-false. 3으로 이동

3. 방문하지 않은 도시들 체크 (1으로 이동)
3-1. 방문한 도시는 패스
3-2. 해당 도시로의 비용이 0인경우 패스
3-3. (방문하지 않은 도시 반환값 + 현재위치에서 방문하지 않은 도시의 비용) 가장 작은 비용으로 대입
3-4. 4로 이동

4. 계산된 비용 반환

 

#include <iostream>
#include <algorithm>
#include <vector>
#include <cstring>
#define MAX_BIT 65536
#define INF 987654321
using namespace std;

int n;
int cost[16][MAX_BIT];
vector<vector<int>> v;

void input()
{
  int num;
  vector<int> temp;

  cin >> n;

  for (int i = 0; i < n; ++i)
  {
    for (int j = 0; j < n; ++j)
    {
      cin >> num;
      temp.push_back(num);
    }
    v.push_back(temp);
    temp.clear();
  }
}

int solve(int location, int visitState)
{
  if (visitState == (1 << n) - 1)
  {
    return v[location][0] ? v[location][0] : INF;
  }

  int &ret = cost[location][visitState];
  if (ret != -1)
  {
    return ret;
  }

  ret = INF;
  for (int i = 0; i < n; ++i)
  {
    if (visitState & (1 << i))
    {
      continue;
    }
    if (v[location][i] == 0)
    {
      continue;
    }

    ret = min(ret, solve(i, visitState | (1 << i)) + v[location][i]);
  }

  return ret;
}

void solution()
{
  memset(cost, -1, sizeof(cost));

  cout << solve(0, 1) << endl;
}

int main(int argc, char *argv[])
{
  input();
  solution();

  return 0;
}

'알고리즘' 카테고리의 다른 글

[C++] 백준 18119번 단어 암기  (0) 2021.03.29
[C++] 백준 14852번 타일 채우기 3  (1) 2021.03.25
[C++] 백준 2234번 성곽  (0) 2021.03.22
[C++] 백준 1062번 가르침  (0) 2021.03.14
[C++] 백준 11723번 집합  (0) 2021.03.14

검색 태그