$N(2 \leq N \leq 15)$명의 사람이 $1$번 구역에서 $2$번 구역으로 이동해야한다.
각 사람에게는 이동시간 $t_i(1 \leq t_i \leq 5000)$가 부여되어있다.
이동하기 위해서는 투명망토를 사용해야 하는데, 투명망토는 한 번에 $2$명씩만 사용할 수 있다. $i$번 사람, $j$번 사람이 이용하였다 했을 때, 이 때 비용은 $max(t_i,\ t_j)$이다. 모든 사람이 $2$번 구역으로 이동하도록 하는 최소 비용을 구하여라. 처음에 모든 사람은 $1$번 구역에 있다.
상태공간을 다음과 같이 정의하자.
$dist(state, flg) =$ 사람들의 현재 위치가 $state$상태이고 $flg = 0$이면 투명망토가 $1$번 구역에, $flg = 1$이면 투명망토가 $2$번 구역에 있을 때 $state = 0$으로부터의 최단거리. 이 때 $state$는 $2$진수로 $i$번째 비트는 $i$번 사람이 $1$번구역에 있다면 $0$, $2$번 구역에 있다면 $1$이다.
상태공간의 크기는 $state$가 $2^{15}$, $flg$가 $2$이므로, 총 $2^{16} \approx 64000$정도이다. 이 때 하나의 상테에서 전이 되는 수는 최대 $_{15}C_2 + 15 \approx 100$개이다. 따라서 정점의 크기가 $N = 2^{16}$, 간선의 크기가 약 $E \approx 2^{16} \times 100$정도인 그래프로 모델링 할 수 있다. 따라서 이 문제는 시간복잡도가 $\mathcal O(ElogV)$인 다익스트라 알고리즘으로 해결할 수 있다.
#include <bits/stdc++.h>
#define ll long long
//#define int long long
const int inf = 1e9;
using namespace std;
typedef array<int, 3> arr;
int n;
int dist[(1 << 15)][2];
vector<int> a;
void dijkstra(int start){
for (int i = 0; i < (1 << n); i++) dist[i][0] = dist[i][1] = inf;
dist[start][0] = 0;
priority_queue<arr, vector<arr>, greater<>> pq;
pq.push({0, start, 0});
while (!pq.empty()){
auto [dis, now, flg] = pq.top(); pq.pop();
if (dis > dist[now][flg]) continue;
if (!flg){
for (int i = 0; i < n; i++){
for (int j = 0; j < n && j != i; j++){
int msk1 = (1 << i);
int msk2 = (1 << j);
if (!(now&msk1) && !(now&msk2)){
int next = now | msk1 | msk2;
int cost = dist[now][flg] + max(a[i], a[j]);
if (cost < dist[next][flg^1]){
dist[next][flg^1] = cost;
pq.push({cost, next, flg^1});
}
}
}
}
} else {
for (int i = 0; i < n; i++){
int msk1 = (1 << i);
if (now&msk1){
int next = now^msk1;
int cost = dist[now][flg] + a[i];
if (cost < dist[next][flg^1]){
dist[next][flg^1] = cost;
pq.push({cost, next, flg^1});
}
}
}
}
}
}
int main(){
ios_base::sync_with_stdio(false);
cin.tie(NULL);
cin >> n;
for (int i = 0; i < n; i++){
int x; cin >> x;
a.push_back(x);
}
dijkstra(0);
cout << dist[(1 << n)-1][1];
return 0;
}