牛客小白月赛34 B. dd爱探险(状压DP)
链接:https://ac.nowcoder.com/acm/contest/11211/B
来源:牛客网
题目描述
星际中有nn个空间站,任意两个空间站间可以相互跳跃,由空间站xx跳跃到空间站yy所需要的代价为P[x][y]P[x][y],注意不保证p[x][y]=p[y][x]p[x][y]=p[y][x],dddd可以任意选择出发的空间站,并通过恰好n−1n−1次跳跃把所有空间站跳完,并且dddd必须选择22次跳跃,其中一次跳跃中进行重力加速,另一次跳跃中进行反重力加速,重力加速会导致当前跳跃代价变为00,反重力加速会导致当前跳跃代价翻倍(乘22),问跳完所有空间站所需要最小代价
输入描述:
第一行一个数n(3≤n≤16)
接下来n行每行n个数,第x行第y个数表示p[x][y](0≤p[x][y]≤100000)
输出描述:
一个数,表示最小代价
示例1
输入
复制
3
0 2 1
2 0 1
3 1 0
输出
复制
2
说明
1->2重力加速
2->3反重力加速
代价0+1*2=2
类似蓝书的最短哈密顿回路的那个题,不同的是需要多设置一维表示当前加速减速的情况。转移方程自然也就不难得出。需要注意的就是初始化边界以及最后的答案要取\(dp[(1 << n) - 1][i][3]\)!
#include <bits/stdc++.h>
using namespace std;
int n, a[20][20], dp[1 << 17][20][5];
//dp[i][j][k]表示当前状态为i, 处于j,且已经:未加减速/一次加速/一次减速/一次加减速
int main() {
cin >> n;
memset(dp, 0x3f, sizeof(dp));
for(int i = 0; i < n; i++) {
for(int j = 0; j < n; j++) {
cin >> a[i][j];
}
}
for(int i = 0; i < n; i++) {
dp[1 << i][i][0] = 0;
}
for(int i = 1; i < (1 << n); i++) {
for(int j = 0; j < n; j++) {//注意这里的编号是0到n - 1
if((i >> j) & 1) {
for(int k = 0; k < n; k++) {
if(((i ^ (1 << j)) >> k) & 1) {//i ^ (1 << j)表示当前状态的上一个状态
dp[i][j][0] = min(dp[i][j][0], dp[i ^ (1 << j)][k][0] + a[k][j]);
dp[i][j][1] = min(min(dp[i][j][1], dp[i ^ (1 << j)][k][0] + 2 * a[k][j]), dp[i ^ (1 << j)][k][1] + a[k][j]);
dp[i][j][2] = min(min(dp[i][j][2], dp[i ^ (1 << j)][k][2]), dp[i ^ (1 << j)][k][2] + a[k][j]);
dp[i][j][3] = min(min(dp[i][j][3], dp[i ^ (1 << j)][k][3] + a[k][j]), dp[i ^ (1 << j)][k][2] + 2 * a[k][j]);
dp[i][j][3] = min(dp[i][j][3], dp[i ^ (1 << j)][k][1]);
}
}
}
}
}
int ans = 0x3f3f3f3f;
for(int i = 0; i < n; i++) {
ans = min(ans, dp[(1 << n) - 1][i][3]);
}
cout << ans;
return 0;
}