状态压缩dp
- 格式:doc
- 大小:83.00 KB
- 文档页数:12
状态压缩动态规划状压DP总述状态压缩动态规划,就是我们俗称的状压DP,是利⽤计算机⼆进制的性质来描述状态的⼀种DP⽅式很多棋盘问题都运⽤到了状压,同时,状压也很经常和BFS及DP连⽤,例题⾥会给出介绍有了状态,DP就⽐较容易了举个例⼦:有⼀个⼤⼩为n*n的农⽥,我们可以在任意处种⽥,现在来描述⼀下某⼀⾏的某种状态:设n = 9;有⼆进制数 100011011(九位),每⼀位表⽰该农⽥是否被占⽤,1表⽰⽤了,0表⽰没⽤,这样⼀种状态就被我们表⽰出来了:见下表列数123456789⼆进制100011011是否⽤√×××√√×√√所以我们最多只需要 2n+1−1 的⼗进制数就好(左边那个数的⼆进制形式是n个1)现在我们有了表⽰状态的⽅法,但⼼⾥也会有些不安:上⾯⽤⼗进制表⽰⼆进制的数,枚举了全部的状态,DP起来复杂度岂不是很⼤?没错,状压其实是⼀种很暴⼒的算法,因为他需要遍历每个状态,所以将会出现2^n的情况数量,不过这并不代表这种⽅法不适⽤:⼀些题⽬可以依照题意,排除不合法的⽅案,使⼀⾏的总⽅案数⼤⼤减少从⽽减少枚举位运算有了状态,我们就需要对状态进⾏操作或访问可是问题来了:我们没法对⼀个⼗进制下的信息访问其内部存储的⼆进制信息,怎么办呢?别忘了,操作系统是⼆进制的,编译器中同样存在⼀种运算符:位运算能帮你解决这个问题(基础,这⾥不打算⾃⼰写了,参照,以下内容也复制⾃qxAi的这篇博客,这⾥谢谢博主)为了更好的理解状压dp,⾸先介绍位运算相关的知识。
1.’&’符号,x&y,会将两个⼗进制数在⼆进制下进⾏与运算,然后返回其⼗进制下的值。
例如3(11)&2(10)=2(10)。
2.’|’符号,x|y,会将两个⼗进制数在⼆进制下进⾏或运算,然后返回其⼗进制下的值。
例如3(11)|2(10)=3(11)。
3.’’符号,x y,会将两个⼗进制数在⼆进制下进⾏异或运算,然后返回其⼗进制下的值。
DP问题不完全总结1.按状态类型分写在前面:从状态类型分,并不表示一题只从属于一类。
其实一类只是一种状态的表示方法。
可以好几种方法组合成一个状态,来解决问题。
1.1.编号(长度)动态规划共性总结本类的状态是基础的基础,大部分的动态规划都要用到它,成为一个维。
一般来说,有两种编号的状态:状态(i)表示前i个元素决策组成的一个状态。
状态(i)表示用到了第i个元素,和其他在1到i-1间的元素,决策组成有的一个状态。
题库a)最长不下降子序列以一元组(i)作为状态,表示第i个作为序列的最后一个点的时候的最长序列。
于是很容易想到O(n2)得算法。
但本题可合理组织状态,引入一个单调的辅助数组,利用单调性二分查找,优化到O(nlogn)。
关于优化详见优化章。
一些问题可将数据有序化,转化成本题。
应用:拦截导弹(NOIP99 Advance 1)就是原题。
Beautiful People(sgu199),要将数据有序化:其中一个权作为第一关键字不下降排列,另一个权作为第二关键字不上升。
Segment(ural 1078),将线段的左端点有序化就可以了。
b)LCS状态(i,j),表示第1个字符串的第i位,与第2个字符串的第j位匹配,得到的最长的串。
若有多个串要LCS,则加维,即几个串就几个维。
我也将此题归入路径问题。
c)花店橱窗布置(IOI99)见路径问题。
1.2.区间动态规划共性总结本类问题与下一章的划分问题的决策的分割点无序交集比较大(占本类问题的30%)。
题库a)石子合并见划分问题b)模版匹配(CEOI01,Patten)这题特殊的地方是状态的值是一个集合而不是一个数。
c)不可分解的编码(ACM World Final 2002)d)Electric Path(ural1143)e)邮局(IOI2000 Day2 1)若状态表示的思路从第i个村庄可以从属于哪个邮局,无最优子结构。
转变一个方向:第k个邮局可以"控制"一个区间的村庄[i,j]。
一道状态压缩DP的详细思路难易指数:★★★河北省衡水中学高亚在动态规划的过程中,状态的表示有时候很是恶心,不容易表示出来,所以,我们需要用一些编码技术,将这些状态表示出来,最常用的方法是用一个二进制数来表示一个集合的状态,下面通过一道例题来对状态压缩DP进行分析一、题目问题描述小keke同学非常喜欢玩俄罗斯方块(**),他最近发现传统的俄罗斯方块很无趣,于是他想到了一个新规则的游戏来考验你。
游戏是这样的:给定你一个宽度为w的游戏场地,我们设高度为正无穷。
现在给你3种俄罗斯方块:1*2的方块2*2的方块2*2的方块去掉一个1*1的方块如果你明白俄罗斯方块的规则的话,方块在下落过程中是可以随便旋转的。
而且是从上往下落,上面的落在下面的上面。
现在给定你一个高度h,让你求出有多少种游戏的方法,使得最后恰好落满h的高度(最上层是齐平的)。
因为这样可以得很多很多分。
输入数据两个整数h,w含义如题所述输出数据一个整数,为能达到要求的游戏方法的总数。
样例输入2 2样例输出3数据范围1<=h,w<=9,注意答案有可能很大(你懂得,用不到高精度)二、关于状态压缩的思路首先,先根据题意,将这个俄罗斯方块的所有形状都画出来(注意这些方块已经标上号了,下面直接引用不加说明)观察到只有七种情况,并且它们的高度只有两行,所以,一个俄罗斯方块最多只会影响上一行或下一行,而不会影响其他行题目中给出的高度,宽度最多只有9,用二进制位完全可以满足要求,所以可以用0表示这个地方是空的,1表示这个地方已经被填充了木块,那么可以很方便的用两个十进制数来表示两行的状态设f[i][j]表示前i行,并且第i行状态为j的最多方案数,那么因为第i行的放置方案仅仅只会影响上一行,所以可以得以下方程:f[i][j]=∑f[i−1][j′]其中,要求第i-1行的j'状态能够推到j这个状态来个最简单的例子,一个2*2的方格,从空的状态到把它填满,方案数是多少?(其实就是样例)可以看到,如果用刚才的方法,直接用0表示不填,用1表示填,那么这三种方案的状态表示是一样的,所以如果只是简单的求和,方案数就只是简单的1,并不是我们想要的结果,如何满足这一点的要求呢?其实可以采用预处理的方法,预处理出从状态i到状态j的方案数有多少种,记录到g[i][j]数组中(如果不能转移到,那么g[i][j] = 0),然后在方程转移的时候,直接采用下面的方程:f[i][j]=∑g[j′][j]∗f[i−1][j′]其中j'还是老规矩,能从j'状态推到j这个状态因为有了g[j'][j]这个从j'状态推到j状态的方案数,所以在i-1行状态为j'时,想推到第i行状态为j,共有g[j'][j]种方案可以选择,根据乘法原理,所以f[i-1][j']的方案数乘以g[j'][j]就可以得到f[i][j],最后针对每种状态,求和即可好了,我主要想说的是如何进行预处理,最后还想说说方程中f数组的初值问题。
状压dp(总结)状态压缩状压这个和二进制分不开关系所以,对于二进制的熟悉是必不可少的技能& 与操作,1不变,0变0| 或操作,0不变,1变1^ 异或操作,0不变,1取反~取反操作,把每一个二进制位0变1,1变0还有一些复杂操作可以根据这些去理解状态压缩所谓状态压缩就是把dp的每一次转移时的状态用二进制来表示或者用二进制来间接表示比如这里有10个苹果,编号1-10我拿走了1,4,7,9这四个苹果那么我们可以用011011010这一串二进制数来表示现在的状态0表示这个位置没有苹果,1表示有那么这就是一个状态相比拿一个bool型的数组,这样表示更方便,内存更小,操作更简单现在我想把拿走的苹果放回去,没拿走的拿走那么状态就变成100100101直接取反 a=011011010 b=100100101a==~b;这时候就充分展示了状态压缩的快捷性下面我们讲一道例题。
在n*n(n≤20)的方格中放置n个车,每个车可以攻击所在的行和列,求方案总数直接上排列组合,n!,很好理解啊在n*n(n≤20)的方格棋盘上放置n 个车,某些格子不能放,求使它们不能互相攻击的方案总数。
这时候一些格子不能放,就要考虑每一行的情况但是,,,,即使每一行中有的格子不能放,最终还是每一行每一列都要有一个车子所以我们用s这个int型的数来表示现在的状态(行状态)如果这一列现在有车子,那这一位就是1所以最终s一定会变成11111111111(全是1)只有这样才能把n个车全部放进去这样这一状态有几个车子说明这就是第几行那这样转移方程就有了dp[s]+=dp[s^(s&-s)];for(;j>0;j-=(j&-j)){dp[i]+=dp[i^(j&(-j))];}还有个问题,有些格子不能放车这怎么办还记得前面的苹果吗用1表示这里能放车子,0表示不可以在状态转移的时候&一下就可以啦j=i&s[num];代码如下#include<bits/stdc++.h>#define ll long longusing namespace std;int n,m;long long dp[1<<20];int s[25];int main(){memset(s,0x7fffffff,sizeof(s));//if(s[1][1]==1)cout<<"sh";//cout<<(s[1][1]&0)<<endl; scanf("%d%d",&n,&m);int x,y;for(int i=1;i<=m;i++){scanf("%d%d",&x,&y);s[x]-=(1<<(y-1));}dp[0]=1;for(int i=1;i<(1<<n);i++){int j,num=0;for(j=i;j>0;j-=(j&(-j))){num++;}j=i&s[num];for(;j>0;j-=(j&-j)){dp[i]+=dp[i^(j&(-j))];}}printf("%lld",dp[(1<<n)-1]);}这样基本的状压dp就结束了也许你已经发现了所有的n都小于等于20因为int只有32位这也是状压的前提所以当你一直为空间时间复杂度着急时就去考虑状压而状压前先找到可以状压的数就是32位以内的over。
周赛350(模拟、脑经急转弯、状压DP、动态规划)难度简单4卡车有两个油箱。
给你两个整数,mainTank 表示主油箱中的燃料(以升为单位),additionalTank 表示副油箱中的燃料(以升为单位)。
该卡车每耗费 1 升燃料都可以行驶 10 km。
每当主油箱使用了 5 升燃料时,如果副油箱至少有 1 升燃料,则会将 1 升燃料从副油箱转移到主油箱。
返回卡车可以行驶的最大距离。
提示:从辅助油箱到主油箱的燃油喷射是不连续的。
每消耗5升燃油,此事件就会突然发生。
示例 1:输入:mainTank = 5, additionalTank = 10输出:60解释:在用掉 5 升燃料后,主油箱中燃料还剩下 (5 - 5 + 1) = 1 升,行驶距离为 50km 。
使用完剩余的1升燃油后,没有新的燃油注入主油箱,主油箱变空。
总行驶距离为 60km 。
示例 2:输入:mainTank = 1, additionalTank = 2输出:10解释:在用完1升燃料后,主燃料箱变空了。
总行驶距离为 10km 。
提示:•1 <= mainTank, additionalTank <= 100模拟classSolution{publicintdistanceTraveled(int mainTank,int additionalTank){int ans=0;while(mainTank >=5){ans +=50;mainTank -=5;if(additionalTank >0){additionalTank -=1;mainTank +=1;}}ans += mainTank *10;return ans;}}数学classSolution{publicintdistanceTraveled(int mainTank,int additionalTank){return(mainTank+Math.min(additionalTank,(mainTank-1)/4))*10;}}难度中等1给你一个正整数数组 nums 。
dp有哪些种类dp有哪些种类⼀、总结⼀句话总结:⼆、dp动态规划分类详解动态规划⼀直是ACM竞赛中的重点,同时⼜是难点,因为该时间效率⾼,代码量少,多元性强,主要考察思维能⼒、建模抽象能⼒、灵活度。
******************************************************************************************动态规划(:Dynamic programming,DP)是⼀种在、和中使⽤的,通过把原问题分解为相对简单的⼦问题的⽅式求解复杂问题的⽅法。
动态规划常常适⽤于有和性质的问题,动态规划⽅法所耗时间往往远少于朴素解法。
动态规划背后的基本思想⾮常简单。
⼤致上,若要解⼀个给定问题,我们需要解其不同部分(即⼦问题),再合并⼦问题的解以得出原问题的解。
通常许多⼦问题⾮常相似,为此动态规划法试图仅仅解决每个⼦问题⼀次,从⽽减少计算量:⼀旦某个给定⼦问题的解已经算出,则将其存储,以便下次需要同⼀个⼦问题解之时直接查表。
这种做法在重复⼦问题的数⽬关于输⼊的规模呈时特别有⽤。
动态规划问题满⾜三⼤重要性质最优⼦结构性质:如果问题的最优解所包含的⼦问题的解也是最优的,我们就称该问题具有最优⼦结构性质(即满⾜最优化原理)。
最优⼦结构性质为动态规划算法解决问题提供了重要线索。
⼦问题重叠性质:⼦问题重叠性质是指在⽤递归算法⾃顶向下对问题进⾏求解时,每次产⽣的⼦问题并不总是新问题,有些⼦问题会被重复计算多次。
动态规划算法正是利⽤了这种⼦问题的重叠性质,对每⼀个⼦问题只计算⼀次,然后将其计算结果保存在⼀个表格中,当再次需要计算已经计算过的⼦问题时,只是在表格中简单地查看⼀下结果,从⽽获得较⾼的效率。
:将各阶段按照⼀定的次序排列好之后,对于某个给定的阶段状态,它以前各阶段的状态⽆法直接影响它未来的决策,⽽只能通过当前的这个状态。
换句话说,每个状态都是过去历史的⼀个完整总结。
dp位运算位运算是计算机中常用的一种操作,它能够对二进制数的每一位进行逻辑运算。
而dp(Dynamic Programming)则是一种常用的算法思想,用于解决复杂的问题。
本文将结合位运算和dp思想,探讨其在算法设计中的应用。
一、位运算的基本操作位运算包括与(&)、或(|)、异或(^)、取反(~)等操作。
这些操作可以对二进制数的每一位进行逻辑运算,用于实现各种功能。
1.1 与运算(&)与运算可以将两个数的对应位相与,结果为1的位表示两个数在该位上都为1,否则为0。
与运算常用于判断某一位是否为1,或者将某一位清零。
1.2 或运算(|)或运算可以将两个数的对应位相或,结果为1的位表示两个数在该位上至少有一个为1。
或运算常用于将某一位设置为1,或者将某一位保持原值。
1.3 异或运算(^)异或运算可以将两个数的对应位进行异或操作,结果为1的位表示两个数在该位上不同,否则为0。
异或运算常用于判断两个数是否相等,或者将某一位取反。
1.4 取反运算(~)取反运算可以将一个数的每一位取反,即0变为1,1变为0。
取反运算常用于将某一位取反,或者将整个数取反。
二、位运算在dp中的应用dp是一种通过将大问题拆分为小问题,并保存中间结果的思想,以降低时间复杂度的方法。
而位运算则可以对大量数据进行高效的处理。
因此,位运算在dp中的应用非常广泛。
2.1 状态压缩在某些问题中,我们需要对集合进行操作,例如求集合的并、交、差等。
而集合可以用二进制数来表示,其中的每一位表示一个元素是否在集合中。
利用位运算,我们可以用一个整数来表示一个集合,从而减少了内存的使用。
2.2 状态转移在一些dp问题中,我们需要求解一个状态的转移过程。
而位运算可以将状态的转移过程转化为对二进制数的位操作。
例如,在旅行商问题中,我们可以用一个二进制数表示城市的访问情况,用位运算来判断某个城市是否已经访问过。
2.3 优化算法位运算还可以用于优化算法的效率。
NOIP中的DP基本类型1、背包模型包括0-1背包、无限背包、有限背包、有价值背包、小数背包(贪心即可)等,是极为经典的模型,其转化与优化也是很重要的。
2、最长非降子序列模型改版:渡河问题、合唱队型等3、最大子段和模型改版:K大子段和、最佳游览,最大子矩阵和等。
4、LCS模型改版:回文字串、多串的LCS等5、括号序列模型改版:关灯问题(TSOJ)、charexp(TSOJ)、最大算式等,核心思想在于以串的长度为阶段。
6、递推模型这类题是属于徘徊在DP与递归之间得一类题,本质是类似于记忆化搜索的一种填表,有很强的数学味。
7、线段覆盖问题改版:Tom的烦恼(TOJ)等。
经常利用到离散化等技巧辅助。
8、单词划分模型和LCS基本上构成了字符串DP的主要类型。
改版:奇怪的门(TOJ)等。
9、股票模型这是DP优化的经典模型。
改版有换外汇等。
10、连续段划分模型即要求把数列划分成k个连续段,使每段和的最大值最小。
改版有任务调度等。
11、游戏模型这类题的阶段(一般是时间)和决策(一般就是游戏目标)很清楚,因此比较容易想到。
改版:免费馅饼(NOI98)、Help Jimmy(CEOI2000)、瑰丽华尔兹(NOI2005,优化需要多费功夫)。
还有就是基础方程式:题目大多数大家可以Google到,且不少是NOI和Vijos原题~~字数关系,就不贴每题的题目了~~1. 资源问题1-----机器分配问题f[i,j]:=max(f[i-1,k]+w[i,j-k]);2. 资源问题2------01背包问题f[i,j]:=max(f[i-1,j-v[i]]+w[i],f[i-1,j]);3. 线性动态规划1-----朴素最长非降子序列f[i]:=max{f[j]+1}4. 剖分问题1-----石子合并f[i,j]:=min(f[i,k]+f[k+1,j]+sum[i,j]);5. 剖分问题2-----多边形剖分f[i,j]:=min(f[i,k]+f[k,j]+a[k]*a[j]*a[i]);6. 剖分问题3------乘积最大f[i,j]:=max(f[k,j-1]*mult[k,i]);7. 资源问题3-----系统可靠性(完全背包)f[i,j]:=max{f[i-1,j-c[i]*k]*P[I,x]};8. 贪心的动态规划1-----快餐问题f[i,j,k]:=max{f[i-1,j',k']+(T[i]-(j-j')*p1-(k-k')*p2) div p3};9. 贪心的动态规划2-----过河 f[i]=min{{f(i-k)} (not stone[i]){f(i-k)}+1} (stone[i]); +贪心压缩状态10. 剖分问题4-----多边形-讨论的动态规划F[i,j]:=max{正正 f[I,k]*f[k+1,j];负负 g[I,k]*f[k+1,j];正负 g[I,k]*f[k+1,j];负正 f[I,k]*g[k+1,j];} g为min11. 树型动态规划1-----加分二叉树 (从两侧到根结点模型)F[i,j]:=max{f[i,k-1]*f[k+1,j]+c[k]};12. 树型动态规划2-----选课 (多叉树转二叉树,自顶向下模型)f[i,j]表示以i为根节点选j门功课得到的最大学分f[i,j]:=max{f[t[i].l,k]+f[t[i].r,j-k-1]+c[i]};13. 计数问题1-----砝码称重f[f[0]+1]=f[j]+k*w[j];(1<=i<=n; 1<=j<=f[0]; 1<=k<=a[i];)14. 递推天地1------核电站问题f[-1]:=1; f[0]:=1;f[i]:=2*f[i-1]-f[i-1-m];15. 递推天地2------数的划分f[i,j]:=f[i-j,j]+f[i-1,j-1];16. 最大子矩阵1-----一最大01子矩阵f[i,j]:=min(f[i-1,j],v[i,j-1],v[i-1,j-1])+1;ans:=maxvalue(f);17. 判定性问题1-----能否被4整除g[1,0]:=true; g[1,1]:=false; g[1,2]:=false; g[1,3]:=false; g[i,j]:=g[i-1,k] and ((k+a[i,p]) mod 4 = j)18. 判定性问题2-----能否被k整除f[i,j±n[i] mod k]:=f[i-1,j]; -k<=j<=k; 1<=i<=n20. 线型动态规划2-----方块消除游戏f[i,i-1,0]:=0f[i,j,k]:=max{f[i,j-1,0]+sqr(len(j)+k), //dof[i,p,k+len[j]]+f[p+1,j-1,0] //not do}; ans:=f[1,m,0];21. 线型动态规划3-----最长公共子串,LCS问题f[i,j]=0 (i=0)&(j=0);f[i-1,j-1]+1 (i>0,j>0,x[i]=y[j]);max{f[i,j-1]+f[i-1,j]}} (i>0,j>0,x[i]<>y[j]);22. 最大子矩阵2-----最大带权01子矩阵O(n^2*m)枚举行的起始,压缩进数列,求最大字段和,遇0则清零23. 资源问题4-----装箱问题(判定性01背包)f[j]:=(f[j] or f[j-v[i]]);24. 数字三角形1-----朴素の数字三角形f[i,j]:=max(f[i+1,j]+a[I,j],f[i+1,j+1]+a[i,j]);25. 数字三角形2-----晴天小猪历险记之Hill同一阶段上暴力动态规划f[i,j]:=min(f[i,j-1],f[i,j+1],f[i-1,j],f[i-1,j-1])+a[i,j];26. 双向动态规划1数字三角形3-----小胖办证f[i,j]:=max(f[i-1,j]+a[i,j],f[i,j-1]+a[i,j],f[i,j+1]+a[i,j]);27. 数字三角形4-----过河卒//边界初始化f[i,j]:=f[i-1,j]+f[i,j-1];28. 数字三角形5-----朴素的打砖块f[i,j,k]:=max(f[i-1,j-k,p]+sum[i,k],f[i,j,k]);29. 数字三角形6-----优化的打砖块f[i,j,k]:=max{g[i-1,j-k,k-1]+sum[i,k]};30. 线性动态规划3-----打鼹鼠’f[i]:=f[j]+1;(abs(x[i]-x[j])+abs(y[i]-y[j])<=t[i]-t[j]);31. 树形动态规划3-----贪吃的九头龙f[i,j,k]:=min(f[x1,j1,1]+f[x2,j-j1-1,k]+d[k,1]*cost[i,fa[i]]] {Small Head}, f[x1,j1,0]+f[x2,j-j1,k]+d[k,0]*cost[i,fa[i]] {Big Head});f[0,0,k]:=0; f[0,j,k]:=max(j>0)d[i,j]:=1 if (i=1) and (j=1)1 if (i=0) and (j=0) and (M=2)0 else32. 状态压缩动态规划1-----炮兵阵地Max(f[Q*(r+1)+k],g[j]+num[k]);If (map[i] and plan[k]=0) and((plan[P] or plan[q]) and plan[k]=0);33. 递推天地3-----情书抄写员f[i]:=f[i-1]+k*f[i-2];34. 递推天地4-----错位排列f[i]:=(i-1)(f[i-2]+f[i-1]);f[n]:=n*f[n-1]+(-1)^(n-2);35. 递推天地5-----直线分平面最大区域数f[n]:=f[n-1]+n:=n*(n+1) div 2 + 1;36. 递推天地6-----折线分平面最大区域数f[n]:=(n-1)(2*n-1)+2*n;37. 递推天地7-----封闭曲线分平面最大区域数f[n]:=f[n-1]+2*(n-1);:=sqr(n)-n+2;38 递推天地8-----凸多边形分三角形方法数f[n]:=C(2*n-2,n-1) div n;对于k边形f[k]:=C(2*k-4,k-2) div (k-1); //(k>=3)39 递推天地9-----Catalan数列一般形式1,1,2,5,14,42,132f[n]:=C(2k,k) div (k+1);40 递推天地10-----彩灯布置排列组合中的环形染色问题f[n]:=f[n-1]*(m-2)+f[n-2]*(m-1); (f[1]:=m; f[2]:=m(m-1);41 线性动态规划4-----找数线性扫描sum:=f[i]+g[j];(if sum=Aim then getout; if sum<Aim then inc(i) else inc(j);)42 线性动态规划5-----隐形的翅膀min:=min{abs(w[i]/w[j]-gold)};if w[i]/w[j]<gold then inc(i) else inc(j);43 剖分问题5-----最大奖励f[i]:=max(f[i],f[j]+(sum[j]-sum[i])*i-t;44 最短路1-----Floydf[i,j]:=max(f[i,j],f[i,k]+f[k,j]);ans[q[i,j,k]]:=ans[q[i,j,k]]+s[i,q[i,j,k]]*s[q[i,j,k],j]/s[i,j];45 剖分问题6-----小H的小屋F[l,m,n]:=f[l-x,m-1,n-k]+S(x,k);46 计数问题2-----陨石的秘密(排列组合中的计数问题)Ans[l1,l2,l3,D]:=f[l1+1,l2,l3,D+1]-f[l1+1,l2,l3,D];F[l1,l2,l3,D]:=Sigma(f[o,p,q,d-1]*f[l1-o,l2-p,l3-q,d]);47 线性动态规划------合唱队形两次F[i]:=max{f[j]+1}+枚举中央结点48 资源问题------明明的预算方案:加花的动态规划f[i,j]:=max(f[i,j],f[l,j-v[i]-v[fb[i]]-v[fa[i]]]+v[i]*p[i]+v[fb[i]]*p[fb[i]]+v[ fa[i]]*p[fa[i]]);49 资源问题-----化工场装箱员50 树形动态规划-----聚会的快乐f[i,2]:=max(f[i,0],f[i,1]);f[i,1]:=sigma(f[t[i]^.son,0]);f[i,0]:=sigma(f[t[i]^.son,3]);51 树形动态规划-----皇宫看守f[i,2]:=max(f[i,0],f[i,1]);f[i,1]:=sigma(f[t[i]^.son,0]);f[i,0]:=sigma(f[t[i]^.son,2]);52 递推天地-----盒子与球f[i,1]:=1;f[i,j]:=j*(f[i-1,j-1]+f[i-1,j]);53 双重动态规划-----有限的基因序列f[i]:=min{f[j]+1}g[c,i,j]:=(g[a,i,j] and g[b,i,j]) or (g[c,i,j]);54 最大子矩阵问题-----居住空间f[i,j,k]:=min(min(min(f[i-1,j,k],f[i,j-1,k]),min(f[i,j,k-1],f[i-1,j-1,k])),min( min(f[i-1,j,k-1],f[i,j-1,k-1]),f[i-1,j-1,k-1]))+1;55 线性动态规划------日程安排f[i]:=max{f[j]}+P[I]; (e[j]<s[i])56 递推天地------组合数C[i,j]:=C[i-1,j]+C[i-1,j-1];C[i,0]:=157 树形动态规划-----有向树k中值问题F[I,r,k]:=max{max{f[l[i],I,j]+f[r[i],I,k-j-1]},f[f[l[i],r,j]+f[r[i],r,k-j]+w[I, r]]};58 树形动态规划-----CTSC 2001选课F[I,j]:=w[i](if i∈P)+f[l[i],k]+f[r[i],m-k](0≤k≤m)(if l[i]<>0);59 线性动态规划-----多重历史f[i,j]:=sigma{f[i-k,j-1]}(if checked);60 背包问题(+-1背包问题+回溯)-----CEOI1998 Substractf[i,j]:=f[i-1,j-a[i]] or f[i-1,j+a[i]];61 线性动态规划(字符串)-----NOI 2000 古城之谜f[i,1,1]:=min{f[i+length(s),2,1], f[i+length(s),1,1]+1};f[i,1,2]:=min{f[i+length(s),1,2]+words[s],f[i+length(s),1,2]+words[s]};62 线性动态规划-----最少单词个数f[i,j]:=max{f[i,j],f[u-1,j-1]+l};63 线型动态规划-----APIO2007 数据备份状态压缩+剪掉每个阶段j前j*2个状态和j*2+200后的状态贪心动态规划f[i]:=min(g[i-2]+s[i],f[i-1]);64 树形动态规划-----APIO2007 风铃f[i]:=f[l]+f[r]+{1 (if c[l]<c[r])};g[i]:=1(d[l]<>d[r]) 0(d[l]=d[r]);g[l]=g[r]=1 then Halt;65 地图动态规划-----NOI 2005 adv19910F[t,i,j]:=max{f[t-1,i-dx[d[[t]],j-dy[d[k]]]+1],f[t-1,i,j];66 地图动态规划-----优化的NOI 2005 adv19910F[k,i,j]:=max{f[k-1,i,p]+1} j-b[k]<=p<=j;67 目标动态规划-----CEOI98 subtraF[I,j]:=f[I-1,j+a[i]] or f[i-1,j-a[i]];68 目标动态规划----- Vijos 1037搭建双塔问题F[value,delta]:=g[value+a[i],delta+a[i]] or g[value,delta-a[i]];69 树形动态规划-----有线电视网f[i,p]:=max(f[i,p],f[i,p-q]+f[j,q]-map[i,j]);leaves[i]>=p>=l, 1<=q<=p;70 地图动态规划-----vijos某题F[i,j]:=min(f[i-1,j-1],f[i,j-1],f[i-1,j]);71 最大子矩阵问题-----最大字段和问题f[i]:=max(f[i-1]+b[i],b[i]); f[1]:=b[1];72 最大子矩阵问题-----最大子立方体问题枚举一组边i的起始,压缩进矩阵 B[I,j]+=a[x,I,j];枚举另外一组边的其实,做最大子矩阵73 括号序列-----线型动态规划f[i,j]:=min(f[i,j],f[i+1,j-1] (s[i]s[j]=”()”or(”[]”)),f[i+1,j+1]+1 (s[j]=”(”or”[” ) , f[i,j-1]+1(s[j]=”)”or”]”);74 棋盘切割-----线型动态规划f[k,x1,y1,x2,y2]=min{min{f[k-1,x1,y1,a,y2]+s[a+1,y1,x2,y2],f[k-1,a+1,y1,x2,y2]+s[x1,y1,a,y2]};75 概率动态规划-----聪聪和可可(NOI2005)x:=p[p[i,j],j];f[I,j]:=(f[x,b[j,k]]+f[x,j])/(l[j]+1)+1;f[I,i]=0;f[x,j]=1;76 概率动态规划-----血缘关系F[A, B]=(f[A0, B]+P[A1, B])/2;f[i,i]=1;f[i,j]=0;(i,j无相同基因)77 线性动态规划-----决斗F[i,j]=(f[i,j] and f[k,j]) and (e[i,k] or e[j,k]); (i<k<j)78 线性动态规划-----舞蹈家F[x,y,k]=min(f[a[k],y,k+1]+w[x,a[k]],f[x,a[k],k+1]+w[y,a[k]]);79 线性动态规划-----积木游戏F[i,a,b,k]=max(f[a+1,b,k],f[i+1,a+1,a+1,k],f[i,a+1,a+1,k]);80 树形动态规划(双次记录)-----NOI2003 逃学的小孩朴素的话枚举节点i和离其最远的两个节点 j,k O(n^2)每个节点记录最大的两个值,并记录这最大值分别是从哪个相邻节点传过来的。
状态压缩的DP方格选数最大hdu2167 (1)给奶牛安排牛场(pku 2241) (4)积木块(哈尔滨5085 bircks) (7)哈密顿回路(pku 2288) (11)排列单词使相同位置的字符最多(pku2817 WordStack) (16)欧拉pizza店(pku3311) (19)炮兵阵地(pku 1185) (22)数a的排列有多少个数可以被b整除(hust SCU-J Counting numbers ) (25)最小矩形覆盖(2836 Rectangular Covering ) (28)4*N的面板用1*2的方格覆盖有多少种(pku 3420) (37)方格选数最大hdu2167题目大意:You're given an unlimited number of pebbles to distribute across an N x N game board (N drawn from [3, 15]), where each square on the board contains some positive point value between 10 and 99, inclusive.给你一个N*N个矩阵,要你选择若干个数,使得最后所选的数总和最大。
选数的规则是如果选了某个数,那么它的八个相邻方向的数都不能选。
本题用到stringstream这样处理起来比较方便。
状态压缩的DP 。
#include<sstream>#include<iostream>using namespace std;int f[2][(1<<15)+10];int num[16][16],v[1<<15],vn,bit[20],line;int st,N;char temp[1024];void init(){int i;memset(bit,0,sizeof(bit));bit[0]=1;for(i=1;i<N;i++){bit[i]=bit[i-1]<<1;}}void valid(){int i,end,j;end=1<<N;bool tag;vn=0;for(i=0;i<end;i++){tag=true;for(j=1;j<N;j++){if((bit[j-1]&i) && (bit[j]&i)){tag=false;break;}}if(tag){for(j=0;j<N;j++){if(bit[j]&i){f[0][i]+=num[0][j];}}v[vn++]=i;}}}void dfs(int x,int s,int t,int p){if(x>=N){if(f[st][t]<f[st^1][s]+p){f[st][t]=f[st^1][s]+p;// printf("%d %d\n",t,f[st][t]);}return;}if(s&bit[x]){dfs(x+2,s,t,p);}else{if(x==0){if((s&bit[x+1])==0){dfs(x+1,s,t,p);dfs(x+2,s,t|bit[x],p+num[line][x]);}else{dfs(x+3,s,t,p);}}else{if(((s&bit[x-1])==0)&&((s&bit[x+1])==0)){dfs(x+1,s,t,p);dfs(x+2,s,t|bit[x],p+num[line][x]);}elsedfs(x+1,s,t,p); //这个漏掉了,一直错,差了好久,分类一定要严密,哎}}}void out(){int i,end=1<<N;for(i=0;i<end;i++)printf("%d ",f[st][i]);printf("\n");}void DP(){memset(f[0],0,sizeof(f[0]));valid();st=0;// out();int j;int end=1<<N;for(line=1;line<=N+1;line++){st=1-st;memset(f[st],-1,sizeof(f[st]));for(j=0;j<vn;j++){if(f[1-st][v[j]]!=-1){// printf("v[j] %d %d\n",v[j],f[1-st][v[j]]);dfs(0,v[j],0,0);}}// out();}printf("%d\n",f[st][0]);}int main(){int i;while(gets(temp)){i=0;do{N=0;stringstream ss(temp);while(ss>>num[i][N])N++;gets(temp);i++;if(temp[0]=='\0')break;}while(true);memset(num[N],0,sizeof(num[N]));init();DP();}return 0;}给奶牛安排牛场(pku 2241)问题描述:N个bull,M个barn,每个bull都有几个自己喜欢的barn,要求为每个bull分配一个barn,使得每个bull所分到的barn都是自己喜欢的,且每个barn至多只能容纳一个bull。
1. 资源问题1-----机器分配问题f[i,j]:=max(f[i-1,k]+w[i,j-k]);2. 资源问题2------01背包问题f[i,j]:=max(f[i-1,j-v[i]]+w[i],f[i-1,j]);3. 线性动态规划1-----朴素最长非降子序列f[i]:=max{f[j]+1}4. 剖分问题1-----石子合并f[i,j]:=min(f[i,k]+f[k+1,j]+sum[i,j]);5. 剖分问题2-----多边形剖分f[i,j]:=min(f[i,k]+f[k,j]+a[k]*a[j]*a[i]);6. 剖分问题3------乘积最大f[i,j]:=max(f[k,j-1]*mult[k,i]);7. 资源问题3-----系统可靠性(完全背包)f[i,j]:=max{f[i-1,j-c[i]*k]*P[I,x]};8. 贪心的动态规划1-----快餐问题f[i,j,k]:=max{f[i-1,j',k']+(T[i]-(j-j')*p1-(k-k')*p2) div p3};9. 贪心的动态规划2-----过河f[i]=min{{f(i-k)} (not stone[i]){f(i-k)}+1} (stone[i]); +贪心压缩状态10. 剖分问题4-----多边形-讨论的动态规划F[i,j]:=max{正正f[I,k]*f[k+1,j];负负g[I,k]*f[k+1,j];正负g[I,k]*f[k+1,j];负正f[I,k]*g[k+1,j];} g为min11. 树型动态规划1-----加分二叉树(从两侧到根结点模型)F[i,j]:=max{f[i,k-1]*f[k+1,j]+c[k]};12. 树型动态规划2-----选课(多叉树转二叉树,自顶向下模型)f[i,j]表示以i为根节点选j门功课得到的最大学分f[i,j]:=max{f[t[i].l,k]+f[t[i].r,j-k-1]+c[i]};13. 计数问题1-----砝码称重f[f[0]+1]=f[j]+k*w[j];(1<=i<=n; 1<=j<=f[0]; 1<=k<=a[i];)14. 递推天地1------核电站问题f[-1]:=1; f[0]:=1;f[i]:=2*f[i-1]-f[i-1-m];15. 递推天地2------数的划分f[i,j]:=f[i-j,j]+f[i-1,j-1];16. 最大子矩阵1-----一最大01子矩阵f[i,j]:=min(f[i-1,j],v[i,j-1],v[i-1,j-1])+1;ans:=maxvalue(f);17. 判定性问题1-----能否被4整除g[1,0]:=true; g[1,1]:=false; g[1,2]:=false; g[1,3]:=false; g[i,j]:=g[i-1,k] and ((k+a[i,p]) mod 4 = j)18. 判定性问题2-----能否被k整除f[i,j±n[i] mod k]:=f[i-1,j]; -k<=j<=k; 1<=i<=n20. 线型动态规划2-----方块消除游戏f[i,i-1,0]:=0f[i,j,k]:=max{f[i,j-1,0]+sqr(len(j)+k), //dof[i,p,k+len[j]]+f[p+1,j-1,0] //not do}; ans:=f[1,m,0];21. 线型动态规划3-----最长公共子串,LCS问题f[i,j]=0 (i=0)&(j=0);f[i-1,j-1]+1 (i>0,j>0,x[i]=y[j]);max{f[i,j-1]+f[i-1,j]}} (i>0,j>0,x[i]<>y[j]);22. 最大子矩阵2-----最大带权01子矩阵O(n^2*m)枚举行的起始,压缩进数列,求最大字段和,遇0则清零23. 资源问题4-----装箱问题(判定性01背包)f[j]:=(f[j] or f[j-v[i]]);24. 数字三角形1-----朴素の数字三角形f[i,j]:=max(f[i+1,j]+a[I,j],f[i+1,j+1]+a[i,j]);25. 数字三角形2-----晴天小猪历险记之Hill同一阶段上暴力动态规划f[i,j]:=min(f[i,j-1],f[i,j+1],f[i-1,j],f[i-1,j-1])+a[i,j];26. 双向动态规划1数字三角形3-----小胖办证f[i,j]:=max(f[i-1,j]+a[i,j],f[i,j-1]+a[i,j],f[i,j+1]+a[i,j]);27. 数字三角形4-----过河卒//边界初始化f[i,j]:=f[i-1,j]+f[i,j-1];28. 数字三角形5-----朴素的打砖块f[i,j,k]:=max(f[i-1,j-k,p]+sum[i,k],f[i,j,k]);29. 数字三角形6-----优化的打砖块f[i,j,k]:=max{g[i-1,j-k,k-1]+sum[i,k]};30. 线性动态规划3-----打鼹鼠’f[i]:=f[j]+1;(abs(x[i]-x[j])+abs(y[i]-y[j])<=t[i]-t[j]);31. 树形动态规划3-----贪吃的九头龙f[i,j,k]:=min(f[x1,j1,1]+f[x2,j-j1-1,k]+d[k,1]*cost[i,fa[i]]] {Small Head}, f[x1,j1,0]+f[x2,j-j1,k]+d[k,0]*cost[i,fa[i]] {Big Head});f[0,0,k]:=0; f[0,j,k]:=max(j>0)d[i,j]:=1 if (i=1) and (j=1)1 if (i=0) and (j=0) and (M=2)0 else32. 状态压缩动态规划1-----炮兵阵地Max(f[Q*(r+1)+k],g[j]+num[k]);If (map[i] and plan[k]=0) and((plan[P] or plan[q]) and plan[k]=0);33. 递推天地3-----情书抄写员f[i]:=f[i-1]+k*f[i-2];34. 递推天地4-----错位排列f[i]:=(i-1)(f[i-2]+f[i-1]);f[n]:=n*f[n-1]+(-1)^(n-2);35. 递推天地5-----直线分平面最大区域数f[n]:=f[n-1]+n:=n*(n+1) div 2 + 1;36. 递推天地6-----折线分平面最大区域数f[n]:=(n-1)(2*n-1)+2*n;37. 递推天地7-----封闭曲线分平面最大区域数f[n]:=f[n-1]+2*(n-1);:=sqr(n)-n+2;38 递推天地8-----凸多边形分三角形方法数f[n]:=C(2*n-2,n-1) div n;对于k边形f[k]:=C(2*k-4,k-2) div (k-1); //(k>=3)39 递推天地9-----Catalan数列一般形式1,1,2,5,14,42,132f[n]:=C(2k,k) div (k+1);40 递推天地10-----彩灯布置排列组合中的环形染色问题f[n]:=f[n-1]*(m-2)+f[n-2]*(m-1); (f[1]:=m; f[2]:=m(m-1);41 线性动态规划4-----找数线性扫描sum:=f[i]+g[j];(if sum=Aim then getout; if sum<Aim then inc(i) else inc(j);)42 线性动态规划5-----隐形的翅膀min:=min{abs(w[i]/w[j]-gold)};if w[i]/w[j]<gold then inc(i) else inc(j);43 剖分问题5-----最大奖励f[i]:=max(f[i],f[j]+(sum[j]-sum[i])*i-t;44 最短路1-----Floydf[i,j]:=max(f[i,j],f[i,k]+f[k,j]);ans[q[i,j,k]]:=ans[q[i,j,k]]+s[i,q[i,j,k]]*s[q[i,j,k],j]/s[i,j];45 剖分问题6-----小H的小屋F[l,m,n]:=f[l-x,m-1,n-k]+S(x,k);46 计数问题2-----陨石的秘密(排列组合中的计数问题)Ans[l1,l2,l3,D]:=f[l1+1,l2,l3,D+1]-f[l1+1,l2,l3,D];F[l1,l2,l3,D]:=Sigma(f[o,p,q,d-1]*f[l1-o,l2-p,l3-q,d]);47 线性动态规划------合唱队形两次F[i]:=max{f[j]+1}+枚举中央结点48 资源问题------明明的预算方案:加花的动态规划f[i,j]:=max(f[i,j],f[l,j-v[i]-v[fb[i]]-v[fa[i]]]+v[i]*p[i]+v[fb[i]]*p[fb[i]]+v[fa[i]]*p[fa[i]]);49 资源问题-----化工场装箱员50 树形动态规划-----聚会的快乐f[i,2]:=max(f[i,0],f[i,1]);f[i,1]:=sigma(f[t[i]^.son,0]);f[i,0]:=sigma(f[t[i]^.son,3]);51 树形动态规划-----皇宫看守f[i,2]:=max(f[i,0],f[i,1]);f[i,1]:=sigma(f[t[i]^.son,0]);f[i,0]:=sigma(f[t[i]^.son,2]);52 递推天地-----盒子与球f[i,1]:=1;f[i,j]:=j*(f[i-1,j-1]+f[i-1,j]);53 双重动态规划-----有限的基因序列f[i]:=min{f[j]+1}g[c,i,j]:=(g[a,i,j] and g[b,i,j]) or (g[c,i,j]);54 最大子矩阵问题-----居住空间f[i,j,k]:=min(min(min(f[i-1,j,k],f[i,j-1,k]),min(f[i,j,k-1],f[i-1,j-1,k])),min(min(f[i-1,j,k-1],f[i,j-1,k-1] ),f[i-1,j-1,k-1]))+1;55 线性动态规划------日程安排f[i]:=max{f[j]}+P[I]; (e[j]<s[i])56 递推天地------组合数C[i,j]:=C[i-1,j]+C[i-1,j-1];C[i,0]:=157 树形动态规划-----有向树k中值问题F[I,r,k]:=max{max{f[l[i],I,j]+f[r[i],I,k-j-1]},f[f[l[i],r,j]+f[r[i],r,k-j]+w[I,r]]};58 树形动态规划-----CTSC 2001选课F[I,j]:=w[i](if i∈P)+f[l[i],k]+f[r[i],m-k](0≤k≤m)(if l[i]<>0);59 线性动态规划-----多重历史f[i,j]:=sigma{f[i-k,j-1]}(if checked);60 背包问题(+-1背包问题+回溯)-----CEOI1998 Substractf[i,j]:=f[i-1,j-a[i]] or f[i-1,j+a[i]];61 线性动态规划(字符串)-----NOI 2000 古城之谜f[i,1,1]:=min{f[i+length(s),2,1], f[i+length(s),1,1]+1};f[i,1,2]:=min{f[i+length(s),1,2]+words[s],f[i+length(s),1,2]+words[s]};62 线性动态规划-----最少单词个数f[i,j]:=max{f[i,j],f[u-1,j-1]+l};63 线型动态规划-----APIO2007 数据备份状态压缩+剪掉每个阶段j前j*2个状态和j*2+200后的状态贪心动态规划f[i]:=min(g[i-2]+s[i],f[i-1]);64 树形动态规划-----APIO2007 风铃f[i]:=f[l]+f[r]+{1 (if c[l]<c[r])};g[i]:=1(d[l]<>d[r]) 0(d[l]=d[r]);g[l]=g[r]=1 then Halt;65 地图动态规划-----NOI 2005 adv19910F[t,i,j]:=max{f[t-1,i-dx[d[[t]],j-dy[d[k]]]+1],f[t-1,i,j];66 地图动态规划-----优化的NOI 2005 adv19910F[k,i,j]:=max{f[k-1,i,p]+1} j-b[k]<=p<=j;67 目标动态规划-----CEOI98 subtraF[I,j]:=f[I-1,j+a[i]] or f[i-1,j-a[i]];68 目标动态规划----- Vijos 1037搭建双塔问题F[value,delta]:=g[value+a[i],delta+a[i]] or g[value,delta-a[i]];69 树形动态规划-----有线电视网f[i,p]:=max(f[i,p],f[i,p-q]+f[j,q]-map[i,j]);leaves[i]>=p>=l, 1<=q<=p;70 地图动态规划-----vijos某题F[i,j]:=min(f[i-1,j-1],f[i,j-1],f[i-1,j]);71 最大子矩阵问题-----最大字段和问题f[i]:=max(f[i-1]+b[i],b[i]); f[1]:=b[1];72 最大子矩阵问题-----最大子立方体问题枚举一组边i的起始,压缩进矩阵B[I,j]+=a[x,I,j];枚举另外一组边的其实,做最大子矩阵73 括号序列-----线型动态规划f[i,j]:=min(f[i,j],f[i+1,j-1] (s[i]s[j]=”()”or(”[]”)),f[i+1,j+1]+1 (s[j]=”(”or”[” ) , f[i,j-1]+1(s[j]=”)”or”]”);74 棋盘切割-----线型动态规划f[k,x1,y1,x2,y2]=min{min{f[k-1,x1,y1,a,y2]+s[a+1,y1,x2,y2],f[k-1,a+1,y1,x2,y2]+s[x1,y1,a,y2]};75 概率动态规划-----聪聪和可可(NOI2005)x:=p[p[i,j],j];f[I,j]:=(f[x,b[j,k]]+f[x,j])/(l[j]+1)+1;f[I,i]=0;f[x,j]=1;76 概率动态规划-----血缘关系F[A, B]=(f[A0, B]+P[A1, B])/2;f[i,i]=1;f[i,j]=0;(i,j无相同基因)77 线性动态规划-----决斗F[i,j]=(f[i,j] and f[k,j]) and (e[i,k] or e[j,k]); (i<k<j)78 线性动态规划-----舞蹈家F[x,y,k]=min(f[a[k],y,k+1]+w[x,a[k]],f[x,a[k],k+1]+w[y,a[k]]);79 线性动态规划-----积木游戏F[i,a,b,k]=max(f[a+1,b,k],f[i+1,a+1,a+1,k],f[i,a+1,a+1,k]);80 树形动态规划(双次记录)-----NOI2003 逃学的小孩朴素的话枚举节点i和离其最远的两个节点j,k O(n^2)每个节点记录最大的两个值,并记录这最大值分别是从哪个相邻节点传过来的。
分组背包问题常见解法
常见的解法包括动态规划和状态压缩。
动态规划解法:
1. 定义`dp[i][j]`表示前i个物品选择j个分组所能获得的最大价值。
2. 初始化`dp`数组为0。
3. 设置状态转移方程为`dp[i][j] = max(dp[i-1][j], dp[i-1][j-group[i].size] + value[i])`,其中`group[i].size`表示第i个物品所属的分组包含的物品数量,`value[i]`表示第i个物品的价值。
4. 依次考虑物品和分组,更新`dp`数组。
5. 最终结果为`dp[n][m]`,其中n表示物品的个数,m表示分组的个数。
状态压缩解法:
1. 定义一个一维数组`dp`表示前i个物品选择j个分组所能获得的最大价值。
2. 初始化`dp`数组为0。
3. 设置状态转移方程为`dp[j] = max(dp[j], dp[j-group[i].size] + value[i])`,其中`group[i].size`表示第i个物品所属的分组包含的物品数量,`value[i]`表示第i个物品的价值。
4. 依次考虑物品和分组,更新`dp`数组。
5. 最终结果为`dp[m]`,其中m表示分组的个数。
状态压缩DP小结最近做了一些状态压缩的动态规划题目,写点感想吧。
FZU1025 Mondriaan’s Dream这道题我认为应该是最基础的状态压缩DP的题目了,所以写详细一点。
题目大意:给出一个矩形的长和宽,求这个矩形用1*2或2*1的方格填满,有多少种放置的方法。
由于长和宽均小于等于11,故每一行均可用一个2进制数表示其状态。
我们用1表示竖放的方格,0表示横放的方格。
那么样例中各行的状态分别为:00100001100111100111001111001100100111001001100110000111000000111100001001100100111001001001110011100001000011转化为十进制,就是268,1948,1945,457,1219,1039,76,1252,1255,67。
用f(i,j)表示第i行状态为j时,有多少种排法。
那么f(i,j)应该等于前i-1行,状态k与j相符的排法数的和。
状态相符,即在j二进制数上为1的位,k一定也为1。
在向下递归时,应该把k中和j二进制状态中同为1的位置为0,即应该求f(i-1,k^j),原因是当第i-1行与第i行相接后,二者同为1的地方消掉了,应该当作0处理。
所以f(i,j)=sigma(f(i-1,k^j),(k^j)==k-j&&check(k)(check(k)表示k是有效的行状态,即二进制数状态中连续的0个数为偶数,可先生成存入数组中)。
所求答案即为f(n,0),初始化f(0,i)=0,f(0,0)=1。
注意结果要用long long或__int64保存,还有要注意位运算的优先级是很低的。
P.S:据说这道题有公式。
PKU1185 炮兵阵地这道题是中文题,意思很容易理解,就不说明题意了。
由于M很小,最多为10,所以可以对行进行状态压缩。
二进制对应位为1表示放炮兵,为0表示空。
我们可以事先生成所有有效的状态,即二进制数任何两个1都要相差两位以上,同时用数组记下此状态有多少个炮兵。
【题目描述】给出一个长度为n(n<=1000)的正整数序列,求一个子序列,使得原序列中任意长度为m 的子串中被选出的元素不超过k(k<=m<=10)个,并且选出的元素之和最大。
【输入数据】第一行三个数n,m,k。
第二行n个数,表示各元素数值大小。
【输出数据】一个数,表示最大元素和。
Sample:Best.in10 4 27 3 4 8 2 6 5 7 4 8Best.out36题目中已规定,m,k 的数据范围都是小于10的,所以我们可以用一个二进制数,来表示一段长度为m的序列,1代表取了那一位,0代表不取,这样就可以用动态规划求解,能够转移的要求是在长度为m的子序列中取的个数,不超过k个,因为总长度不会超过1000,所以是可以过的,我们用位运算会使速度更快。
所附的程序代码中,f[i,j]代表取到第i个,前m个(including i)的状态是j,g[i,j]代表这样一个状态,中取了多少个。
program civi;typeinteger=longint;varf,g:array[0..1001,0..1 shl 11]of integer;a:array[1..1001]of integer;n,m,k,i,j,jj:integer;beginassign(input,'best.in');reset(input);readln(n,m,k);for i:=1 to n doread(a[i]);fillchar(f,sizeof(f),$ff);fillchar(g,sizeof(g),0);f[0,0]:=0;for i:=0 to n-1 dofor j:=0 to 1 shl m-1 doif f[i,j]<>-1 thenbeginif j and 1=1 then dec(g[i,j]);jj:=j shr 1;if g[i,j]<=k thenif f[i+1,jj]<f[i,j] then beginf[i+1,jj]:=f[i,j];g[i+1,jj]:=g[i,j];end;if g[i,j]<k thenif f[i+1,jj+1 shl (m-1)]<f[i,j]+a[i+1] thenbeginf[i+1,jj+1 shl (m-1)]:=f[i,j]+a[i+1];g[i+1,jj+1 shl (m-1)]:=g[i,j]+1;end;end;k:=0;for j:=0 to 1 shl m-1 doif f[n,j]>k then k:=f[n,j];assign(output,'best.out');rewrite(output);writeln(k);close(output);end.动态规划本来就很抽象,状态的设定和状态的转移都不好把握,而状态压缩的动态规划解决的就是那种状态很多,不容易用一般的方法表示的动态规划问题,这个就更加的难于把握了。
状态压缩dp炮兵阵地Time Limit: 2000MS Memory Limit: 65536KTotal Submissions: 8971 Accepted: 3169Description司令部的将军们打算在N*M的网格地图上部署他们的炮兵部队。
一个N*M的地图由N行M列组成,地图的每一格可能是山地(用"H" 表示),也可能是平原(用"P"表示),如下图。
在每一格平原地形上最多可以布置一支炮兵部队(山地上不能够部署炮兵部队);一支炮兵部队在地图上的攻击范围如图中黑色区域所示:如果在地图中的灰色所标识的平原上部署一支炮兵部队,则图中的黑色的网格表示它能够攻击到的区域:沿横向左右各两格,沿纵向上下各两格。
图上其它白色网格均攻击不到。
从图上可见炮兵的攻击范围不受地形的影响。
现在,将军们规划如何部署炮兵部队,在防止误伤的前提下(保证任何两支炮兵部队之间不能互相攻击,即任何一支炮兵部队都不在其他支炮兵部队的攻击范围内),在整个地图区域内最多能够摆放多少我军的炮兵部队。
Input第一行包含两个由空格分割开的正整数,分别表示N和M;接下来的N行,每一行含有连续的M个字符('P'或者'H'),中间没有空格。
按顺序表示地图中每一行的数据。
N <= 100;M <= 10。
Output仅一行,包含一个整数K,表示最多能摆放的炮兵部队的数量。
Sample Input5 4PHPPPPHHPPPPPHPPPHHPSample Output6SourceNoi 01这道题是一道典型的状态压缩DP。
注意到每一行炮兵的摆放只和前两行有关系,便可以记录一个f数组,f[h,i,j]表示第h行的状态为st[i],第h-1行的状态为st[j]。
现在的关键就是如何快速求f[h,i,j]。
注意到求f数组跟状态数有关,那么便优化状态。
首先是状态的存储。
注意到m范围较小,便可以按行存储。
对于每一行,如果一个格子放了炮兵,就看成1,否则看成0,然后记下对应数列的十进制值即可。
但这样共有2^m种状态,显然太多了。
注意到有很多状态其实是不可能的(即某个炮兵附近还有炮兵),我们就可以再预处理状态时加一些判断。
那么如何高效判断呢?对了,可以用位运算!判断过程如下:for i:=0 to 1 shl m-1 dobeginif i and (i shl 1)<>0 then continue;//错一位进行判断if i and (i shl 2)<>0 then continue;//错两位进行判断inc(sl);st[sl]:=i;count[sl]:=calc(i);//count数组记录每个序列中1的个数end;解决了存储问题后,整个程序就很简单了,剩下的DP不再赘述,详见程序。
贴代码:/code/view/18264/var f:array[1..100,1..70,1..70] of integer;map:array[1..100] of integer;st,count:array[1..70] of integer;n,m,sl:integer;function calc(x:integer):integer;var sum:integer;beginsum:=0;while x<>0dobeginsum:=sum+x mod2;x:=x shr1;end;exit(sum);end;procedure init;var i,j:integer;ch:char;beginreadln(n,m);sl:=0;for i:=0to1shl m-1dobeginif i and (i shl1)<>0then continue;if i and (i shl2)<>0then continue;inc(sl);st[sl]:=i;count[sl]:=calc(i);end;for i:=1to n dobeginmap[i]:=0;for j:=1to m dobeginread(ch);if ch='H'then map[i]:=map[i]+1shl (m-j);end;readln;end;end;function max(a,b:integer):integer;beginif a>b then exit(a) else exit(b);end;procedure work;var h,i,j,k:integer;beginfor i:=1to n dofor j:=1to sl dofor k:=1to sl dof[i,j,k]:=-1;for i:=1to sl doif map[1] and st[i]=0then f[1,i,1]:=count[i];for h:=2to n dofor i:=1to sl doif st[i] and map[h]=0thenfor j:=1to sl doif st[j] and st[i]=0thenfor k:=1to sl doif (st[k] and st[i]=0) and (st[k] and st[j]=0) thenif f[h-1,j,k]<>-1thenf[h,i,j]:=max(f[h,i,j],f[h-1,j,k]+count[i]); end;procedure print;var i,j,ans:integer;beginans:=0;for i:=1to sl dofor j:=1to sl doans:=max(ans,f[n,i,j]);writeln(ans);end;begininit;work;print;end.poj1038(状态压缩dp)DescriptionBugs Integrated, Inc. is a major manufacturer of advanced memory chips. They are launching production of a new six terabyte Q-RAM chip. Each chip consists of six unit squares arranged in a form of a 2*3 rectangle. The way Q-RAM chips are made is such that one takes a rectangular plate of silicon divided into N*M unit squares. Then all squares are tested carefully and the bad ones are marked with a black marker.Finally, the plate of silicon is cut into memory chips. Each chip consists of 2*3 (or 3*2) unit squares. Of course, no chip can contain any bad (marked) squares. It might not be possible to cut the plate so that every good unit square is a part of some memory chip. The corporation wants to waste as little good squares as possible. Therefore they would like to know how to cut the plate to make the maximum number of chips possible.TaskY ou are given the dimensions of several silicon plates and a list of all bad unit squares for each plate. Y our task is to write a program that computes for each plate the maximum number of chips that can be cut out of the plate.InputThe first line of the input file consists of a single integer D (1 <= D <= 5), denoting the number of silicon plates. D blocks follow, each describing one silicon plate. The first line of each block contains three integers N (1 <= N <= 150), M (1 <= M <= 10), K (0 <= K <= MN) separated by single spaces. N is the length of the plate, M is its height and K is the number of bad squares in the plate. The following K lines contain a list of bad squares. Each line consists of two integers x andy (1 <= x <= N, 1 <= y <= M) ?coordinates of one bad square (the upper left square has coordinates [1, 1], the bottom right is [N,M]).OutputFor each plate in the input file output a single line containing the maximum number of memory chips that can be cut out of the plate.Sample Input26 6 51 44 62 23 66 46 5 43 36 16 26 4Sample Output34SourceCEOI 20022008-08-30 20:40题意如下:Bug Integrated公司正准备生产6TB的Q-RAM芯片,每块芯片都是由2*3的小芯片组成的。