Loading

牛客小白月赛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;
}
posted @ 2021-06-03 10:05  脂环  阅读(71)  评论(0编辑  收藏  举报