通常将以一个集合内的元素信息作为状态且状态总数为指数级别的动态规划称为状态压缩动态规划。
其是一类以集合信息为状态的特殊的动态规划问题,主要有传统集合动态规划与基于连通性状态压缩的动态规划两种。
其原理是通过二进制位运算将状态压缩(用整数表示集合)作为动态规划的状态来解决问题。
通常具备以下两个特点:
在任意时刻,已经求出最优解的状态与尚未求出最优解的状态在各维度上的分界点组成了 DP 扩展的轮廓,对于某些问题,需要在动态规划的状态中记录一个集合,保存这个轮廓的详细信息,以便进行状态转移。
若集合大小不超过 n n n,集合中每个元素都是小于 k k k 的自然数,则可以把这个集合看作一个 n n n 位 k k k 进制数,以一个 [ 0 , k n − 1 ] [0,k^n-1] [0,kn−1] 之间的十进制整数的形式作为 DP 状态的一维。
为更好的理解状压 DP,首先要有相关的位运算知识:点击这里。
1.状压 DP 题型
1)数据 n ≤ 16 n≤16 n≤16 ,但状态总数可达指数级
2)满足无后效性原则,通过前面的状态知道后面的怎么选,用 1、0 来记录状态是否存在
2.一般定义二维数组
第一维是第几排(如:铺砖块等)
第二维标识状态,0 或 1
3.数组初始化
根据题设设置初值,一般为 memset(dp,127,sizeof(dp));
再进行状态更新:
for(int i = 0; i < n; i++)
dp[i][1<<i] = 0;
表示 i i i 在 s t a t e state state 中存在,这里的 1 < < i 1<1<<i 就是一种只选 i i i 的 s t a t e state state
4.枚举状态循环求值
for(int i = 1; i <= n; i++)
{
for(int j = 0; j < (1<<m); j++)
{
if(check(i,j)) //判断当前行满足条件的state
{
for(int k = 0; k < (1<<m); k++) //枚举上一行的pre_state进行更新
{
...
}
}
}
}
5.判断状态中的每一个是否符合要求
for(int i = sum; i != 0; i = (i-1)&sum)
{
...
}