状压 2

状压

状态压缩,就是用一个整数代替DP中某种一般情况下需要以集合充当状态的状态
因为要枚举集合,所以时间复杂度就是指数级
状压意义下的状态表示就是在\(P\)进制下将第\(i\)个元素的某种状态用整数第\(i\)位的\(j∈[0,P-1]\)表示出来
一般而言,状态压缩顾名思义压缩的是一整个集合表示当前状态
但是,也有没有阶段的时候,这个时候按照数从小到大枚举显然会把所有集合更新一遍
或者是说考虑前\(i\)个物品的这个阶段被压掉了没有用

不同状态之间的转移需要用相应的位运算实现

一般的处理步骤?

预处理

首先预处理出各种可行的状态以及相应的权值
然后去各种状态转移

枚举

这就挺简单的了,将各种可行状态套状态转移方程直接算就行了

状态转移方程

状压的状态转移方程挺难适应的,主要是压缩里面的位运算
别的就阶段状态决策列出来状态转移方程就挺好整的了
注意好限制转移条件和可行决策的枚举就没别的了
似乎确实比优化直白但就是优化比状压难不知道为啥可能虚标了吧

例题

互不侵犯

棋盘问题一般以行号为阶段,所有的可行状态为状态
所以就以行号\(i\)为阶段,当前可行状态\(kx[j]\)为状态
决策?
根据题意,我们还需要为上一行的某个状态挑选当前的一个状态为决策,
不过这和设计相违背
反过来,设计上一行的一个状态为决策,就非常好整了
根据加法原理,我们知道:
状态转移方程:
\(f_{i,j,now}[i][kx[j][now]=\sum\limits^{k}_{now=sum[j]}f[i-1][k][now-sum[j]]\)
\(i\)是行号,\(j\)当前可行状态,\(k\)上行可行状态,额外维护的一些东西是对于数量限制
\(now\),当前的国王数,\(sum[j]\)当前可行状态下的国王数
转移条件用位运算表示就是 j&(k<<1)==0 and j&k==0 and j&(k>>1)==0
终值:\(\sum\limits^{cnt}_{i=1}f[n][i][k]\)
初值:\(f[0][1][0]=1\)

以及一些预处理小技巧
定义\(kx[i]\)为第\(i\)个可行状态,\(cnt\)为可行状态总数
首先行内预处理\(kx\)数组
枚举从\(1\)\(2^n-1\)
\(kx[i]\)的二进制表示下第\(j\)位为\(0\)表示无国王,\(1\)有国王
只考虑行内所以\(kx[i]\)每个\(1\)左右必须是\(0\)
这个可以通过左右移1解决:如果原数按位与上左右移1的数不为\(0\)不可行

炮兵阵地

差不多,问最大值
预处理的还是行内所有可行状态以及个数
行号阶段,可行状态做状态,决策和上两行有关系,这里保存的决策上一行状态
首先预处理出地形上的矛盾:
可放为0,不可放为1
为节省空间把每行的地形状态作为限制条件
然后就是状态转移方程:
\(f[i][j][k1]=max(f[i][j][k1],f[i-1][k1][k2]+kx[j])\)
\(i\)行号,\(j\)当前状态,\(k1,k2\)上一行和上两行状态
条件就直接与起来就行

疾病管理

直接状压
每头牛的表示就是每一位患病是1没病是0
然后就是直接枚举状态
全集就是当前状态,每头牛的表示必然是全集的子集
判断直接或一下就行
最后找到最大值就行

愤怒的小鸟

预处理一下一条抛物线能够打到绿猪的集合
预处理完了之后就是经典的考虑 \(f_{S}\) 表示已经打到的集合所用抛物线的最小值
考虑一条抛物线 \(S'\cup S=S\)
那么有状态转移方程 \(f_{S}=min_{S'}(f_{S\S'}+1)\)
这个抛物线的决策是可以通过枚举两个点 \(i\)\(j\) 确定的,
同时也可以确定在这条抛物线上的其他点,\(O(n^3)\) 的复杂度预处理一下即可

Bill的挑战

这个就要考虑 \(f_{i,S}\) 表示当前已经确定前 \(i\) 位,保持正确匹配的集合为 \(S\) 的方案数
考虑枚举每一位填的决策,这个决策会导致这一位匹配的集合为 \(S'\)
那么就会有 \(f_{i+1,S_{i+1}}=\sum\limits_{S_i\cap S'=S_{i+1}}f_{i,S_i}\)
实际上,预处理一下每一位决策对应的集合可以得到 \(S'\) 在每一位的个数不过 \(|\Sigma|\)
最后统计答案的时候只需要看 \(\sum\limits_{|S|=k}f_{n,S}\) 即可
总时间复杂度就是 \(n|\Simga|2^k\)

posted @ 2022-05-14 22:18  2K22  阅读(48)  评论(1)    收藏  举报