前言
状态压缩让我们回到了计算机的本质——二进制运算,对于一些数据范围较小但状态较多的题目,我们可以用状压DP解决。
概念
我们可以考虑用二进制表示状态,二进制上每一位表示整个决策集合中的第i个决策是否进行,设一共有$m$中决策,我们枚举$0 \sim 2^m-1$中所有数,找出所有状态中的最优状态并进行$DP$即可。
模板
矩阵状压DP模板
一般来说,我们用dp数组记录当前行数、上一行状态、本行状态,
for(re int i=1;i<=n;++i) {//枚举当前所在的行数
for(re int L=0;L<MAXN;++L) { //枚举上一行的状态,MAXN表示状态的总数
if(...) continue;//如果上一行不满足约束条件,进入下一状态
for(re int S=0;S<MAXN;++S) {//枚举当前行的状态
if(...) continue;
dp[i][S][...]=dp[i-1][L][...];//状态转移
}
}
}
数列状压DP模板
一般来说,我们运用刷表法,由已知状态推导到答案
for(re int S=0;S<MAXN;++S) {//S表示状态,其中二进制为1表示在数列中,MAXN表示最大状态数
for(re int i=1;i<=n;++i) {//枚举下一个加入数列的节点
if(S&(1<<i)) continue;//已经在状态中,不用管
dp[S^(1<<i)]=dp[S]+...//状态转移方程
}
}
例题
P1879 [USACO06NOV]Corn Fields G(题解)(我的代码)
本题是矩阵状压DP入门题,我们可以用dp方程的两个维度分别表示[行数][当前行的状态]下的答案数,最后统计最后一行的总和记为答案。
P1896 [SCOI2005]互不侵犯(题解)(我的代码)
本题属于状压DP基础题,我们可以设dp方程的三个维度分别为[当前行数][这一行所表示的状态][包括这一行已经用的国王数],然后将第一行国王不相邻的状态赋值为$1$,之后不断累加方案数,最后统计最后一行的状态数总数即为答案。
P2704 [NOI2001] 炮兵阵地(题解)(我的代码)
本题中我们可以用二进制数记录每一行上的每一个点是否放置炮兵,再利用$<<$和$&$运算计算炮兵之间是否会互相攻击,用dp数组存每个状态下最多能放置的炮兵数,最后统计答案即可。
本题是数列状压,我们可以用状压枚举乐队的排列顺序,令f[状态]表示该状态下最少出队人数,然后用刷表法(由当前状态推导未知状态)枚举下一个加入乐团的编号,统计最小出队人数即可。
P7519 [省选联考 2021 A/B 卷] 滚榜(题解)(我的代码)
本题我们可以提前计算费用,因为$b_i$是单调不降的,所以我们可以只用$b_i$补齐当前第一与前一次第一的差值,再将之后的每一支队伍都加上当前补齐值即可。
参考资料
标签:状态,题解,状压,笔记,DP,一行,本题 来源: https://www.cnblogs.com/wujianxiang/p/15103732.html
本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享; 2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关; 3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关; 4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除; 5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。