状态压缩DP

文章介绍了如何在动态规划问题中使用状态压缩技术,以减少状态维度,特别以旅行商问题、矩阵拼接和三进制状态压缩为例,展示了如何通过位运算表示复杂状态并进行状态转移。最后提到了相关练习题目如P14332831270418791896309236944925215721672396436350052150。
摘要由CSDN通过智能技术生成

代码

一般集合

dp[1][0] = 0; //开始:集合中只有点0,起点和终点都是0

for (int S = 1; S < (1 << n); S++) { // 枚举每一种可能 
	for (int j = 0; j < n; j++) { // 枚举每一个点 
		if ((S >> j) & 1) { // 这个点存在 
			for (int k = 0; k < n; k++) {
				if ((S ^ (1 << j)) >> k & 1) { // k属于集合S - j 
					dp[S][j] = min(dp[S][j], dp[S ^ (1 << j)][k] + dist[k][i]); // 中转 
				}
			}
		}
	}
} 

轮廓线(二维填充)

1、重点是对轮廓线附近的状态进行分析,得到状态转移方程

2、滚动数组(基本上固定的)



swap(n, m); // 复杂度为n * m * 2 ^ m , 所以m越小,越有利 
// 初始化 
dp[now][(1 << m) - 1] = 1; 

for (int i = 0; i < n; i++) {
	for (int j = 0; j < m; j++) {
		
		swap(now, old); // 滚动数组,now始终指向最新的一行
		
		memset(dp[now], 0, sizeof dp[now]);
		// 枚举这个点的上一行的所有状态 
		for (int k = 0; k < (1 << m); k++) {
			if (k & 1 << (m - 1)) {
				// k5 = 1时候x = 0 ,       k5为i,j上面的点(i - 1,j)的状态,1表示填充, 0表示没有填充, 
				if (k & 1 << (m - 1)) {
					dp[now][(k << 1) & (~(1 << m))] += dp[old][k];    // k = k5 k4 k3 k2 k1 k0   ~(1 << m))这个的功能代表去除越界(长度超过6)的1 
				}
				// k5 = 0 时候 x = 1,,    i != 0 代表 i 不是第一行,第一行没法加上面的   k5 等于0 时候,x 不许等于1 
				if (i && !(k & 1 << (m - 1))) {
					dp[now][(k << 1) ^ 1] += dp[old][k]; 
				}
				// x = 0,k5 = 1, k0 = 0  不能是第一列,第一列没法加左边的 
				if (j && (!(k & 1)) && (k & 1 << (m - 1))) {
					dp[now][((k << 1) | 3) & (~(1 << m))] += dp[old][k];
				}
				 
			}
		} 
	}
}
// 最后的 dp[i - 1][j - 1][(k << m) - 1] 就是答案 从0开始存的 
/* 解释  
k = k5 k4 k3 k2 k1 k0 代表组合 
k & 1 << (m - 1) 代表k5 = 1
(~(1 << m))  这个的功能代表去除越界(长度超过6)的1 
k << 1 最左边的一个k5不要了 
(k << 1) ^ 1   ^ 是相同为0,不同为1的, 所以这句话是k左右边的变成1 
((k << 1) | 3)  将k右边两个位都变成 1 (因为左右一起组合)
*/ 

原理

动态规划的题目中,状态的表示是解题的关键。在一些dp问题中,状态可能会非常复杂,导致用来存储状态的dp数组会有很多维。为此,我们需要用过状态压缩来达到减少状态维数的目的。在状态压缩dp中,灵活运用位运算是一项必不可少的要求。

核心

动态规划问题当中,复杂度等于状态数乘上决策数

状态数 = 集合的状态 + 我们现在所处的地方

if 判断 这个是否在状态里面

位运算 

题目

1、旅行商(上面代码为此代码)

2、poj2411 (矩阵拼接)(轮廓线模式,上为代码)

3、三进制状态压缩  hdu3001

4、棋盘dp--最小三角路径

状态转移:
dp[i][j] = grid[i][j] + min(dp[i - 1][j], dp[i - 1][j - 1])

练习:

洛谷p 1433 2831 2704 1879 1896 3092 3694 4925 2157 2167 2396 4363 5005 2150

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值