随笔分类 -  动态规划

摘要:树型DP入门题题目链接:http://acm.sjtu.edu.cn/OnlineJudge/problem/1077•设f(i,j)中序遍历为i,i+1,…,j的二叉树的最大加分,则有: f(i,j)=max{f[i,k-1]*f[k+1,j] +d[k]}•显然 f(i,i)=d[i]•答案为f(1,n)•1<=i<=k=<=j<=n•时间复杂度 O(n3)•要构造这个树,只需记录每次的决策值,令b(i,j)=k,表示中序遍历为i,i+1,…,j的二叉树的取最优决策时的根结点为k最后前序遍历这个树即可。/*树型DP*/#include <cstdio># 阅读全文
posted @ 2013-03-18 19:05 Titanium 阅读(857) 评论(0) 推荐(0)
摘要:状态压缩DP经典覆盖问题,输入n和m表示一个n*m的矩形,用1*2的方块进行覆盖,不能重叠,不能越出矩形边界,问完全覆盖完整个矩形有多少种不同的方案其中n和m均为奇数的话,矩形面积就是奇数,可知是不可能完全覆盖的。接着我们来看n*m为偶数的情况DP前先处理一下,交换n和m使n较大m较小,这样能减少状态数另外数据中是有重复的,所以开辟一个ans数组来记录每组数据的结果,如果遇到相同的数据则不要计算直接输出答案不用这个ans数组的话也不会超时,这个代码是跑出了950ms,加了这个记录答案的数组时间变为600ms接着就看注释部分的讲解即可/*最上面的为第1行,最下面为第n行从上到下按行DP其中一行的 阅读全文
posted @ 2013-03-14 22:08 Titanium 阅读(4041) 评论(0) 推荐(2)
摘要:状态压缩DP多数也把这题分类在图论中,算是状态压缩在图论中的一个应用题意:有n只牛和m个场,下面n行给出每只牛喜欢去的场的个数,再给出每个场的编号(而且每只牛只能去他们喜欢的场)。然后要你安排好这些牛去他们喜欢的场,一个场只能有一只牛,问有多少种分配方案状态压缩,定义一个m位长的二进制数,从右到左依次代表第1,第2,第3个场,1表示这个场已经被占用,0表示没有。最后我们是要把n个牛都安排进去,那么这个二进制数将有n个1,这些就是我们要的目标状态。显然我们是按照牛的个数进行DP,先放第1只牛,再放第2只……最后放第n只。所以状态转移可以表示为 s'--->s , 其中s‘有k-1个 阅读全文
posted @ 2013-03-13 18:55 Titanium 阅读(343) 评论(0) 推荐(0)
摘要:动态规划(递推)选拔赛的题目,也是2012国赛的题目。题意:给n个节点,构建一棵树,使到同一层的节点所拥有的子节点数相等,问能构建出多少个这句话,“使到同一层的节点所拥有的子节点数相等”,并没有把话说得很白,但是细想就可以发现,这句话是等同于说,这棵树是对称,而且非常对称,甚至可以想象到,以树根为轴,把树劈成两份,两边是对称的,取其中一边,再以树根劈开,两边还是对称的(这样强的对称性才满足题目说的那句话)所以基于这点,我们可以想到,除开树根外,下面的子树(可能一棵子树,或者两棵,多棵),一定要完全相同的,为什么?哪怕每棵子树是对称的,但是子树与子树之间不同,那么都挂在树根上的时候,是不能满足 阅读全文
posted @ 2013-03-10 21:26 Titanium 阅读(834) 评论(0) 推荐(0)
摘要:动态规划去年选拔赛的一个题目,题意就是给一个序列,要找出一个子序列,一增一减(第偶数个元素要比它前面的元素小,第奇数个元素要比它前面的元素大)算是比较基础的DP,属于"第i个元素与它前面i-1的元素形成的一种关系,最后变为前i个元素的信息"dp[i]表示加入第i个数字,与前i-1个数字能形成的最大长度,因此面对两个两个问题,第i个元素会不会加入到最终的最长子序列中,要加的话怎么加先看方程 dp[i]=max{ dp[j] } + 1; 若dp[j]为奇数,若想加入第i个元素,那么第i个元素将会是子序列中的第偶数个元素,那么还要满足a[i]<a[j]若dp[j]为偶数, 阅读全文
posted @ 2013-03-10 10:49 Titanium 阅读(252) 评论(0) 推荐(0)
摘要:状态压缩DP题意:输入n,m,一个n*n的棋盘,放入m个国王,国王不能相互攻击,有多少种放置的可能。国际象棋的国王的攻击范围就是它周围的一圈,一共8个格子(上下左右四个对角)和 poj 1185 炮兵布阵 非常相似 , 同样使用位运算加速,同样可以使用滚动数组代码有详细注释/*state[i]表示第i种状态,即一行内的国王不互相攻击的状态,king[i]对应这种状态有多少个国王关于相邻两行的状态是否能共存的问题,也就是两行的国王会不会相互攻击,state[k]表示第i行的状态,state[kk]表示第i-1行的状态state[k] & state[kk] = 1 , 说明在某一列上有国 阅读全文
posted @ 2013-03-07 23:03 Titanium 阅读(336) 评论(0) 推荐(0)
摘要:动态规划1.先考虑在1到n的村长里面放一个邮局的最优解,那么就是把邮局放在最中间的那个村庄处最优(若村庄数为偶数则最中间的村庄有两个哪个都可以)2.当放m个邮局的时候,其他每个邮局相当于有一个控制范围,范围内的村庄离该邮局最近,那么m个邮局会把n个村庄分为m块,我们就是dp每一块,令每一块的值最优,以及加上还没有处理的大块的最优解,则是我们要的答案dp[i][j]表示从1号到i号村庄放j个邮局的最优解方程:dp[i][j]=min{ dp[k-1][j-1]+s[k][i] } s[k][i]表示在k号村庄到i号村庄放1个邮局的最优解,也就是放在最中间记忆化搜索/*dp[i][j]=min{. 阅读全文
posted @ 2013-03-06 15:51 Titanium 阅读(197) 评论(0) 推荐(0)
摘要:动态规划题意:让你猜一个物品的价格,猜低了或者猜高了都会提示你。G,L,表示你有G次机会猜一个数,如果猜错了,G会减少1次,如果你的错误是应该是猜高了,那么L也会少一次(猜低了L不会少)。如果G次机会都用完了,则输;若G次机会还有剩余,而L次机会用完了,这时再猜一个数,若猜高了,那么也输了。让你确定一个数字N,以保证在G,L的条件下,你一定能猜到[1,N]以内的任何一个数1.如果L等于0,也就是说你在猜的过程中,绝对不能猜高,所以你只能从1开始猜,并依次为2,3,4……最大能猜到的数是G,所以N=G,这样才能保证你一定能猜到其中的任何一个数2.L>G,这是个迷惑的情况,其实L比G大是没意 阅读全文
posted @ 2013-03-05 19:05 Titanium 阅读(660) 评论(2) 推荐(0)
摘要:动态规划一开始定义为dp[l1][l2][l3][dd],表示用l1个{},l2个[],l3个(),深度为dd的方案数,后来不行。参考别人后,dp[l1][l2][l3][dd]表示深度小于等于dd的方案数,那么答案是dp[l1][l2][l3][dd]-dp[l1][l2][l3][dd-1]可以用分块和整块的思想来看这个问题好像[[()][]] 这类的我们可以说它是整块,[][](),这类的我们可以说它是分块,我们在构建的dp数组的时候就是把其当做是分块来处理,然后使用乘法原理例如dp[l1][l2][l3][dd],我们可以先构建一个小分块,用小分块的方案数*其实括号能组成的方案数,而这 阅读全文
posted @ 2013-03-03 11:20 Titanium 阅读(628) 评论(0) 推荐(0)
摘要:动态规划poj 1141 ural 1183 zoj 1463 都是相同的题目,黑书DP的例题输入比较恶心,有空串。递推的时间是1s多,记忆化的时间是4.3s勉强过,原理不说了百度各种有/*1.dp[i][j]=dp[i+1][j-1] , p[i][j]=-1 , --->p[i+1][j-1]2.dp[i][j]=dp[i+1][j]+1 , p[i][j]=-2 , --->p[i+1][j]3.dp[i][j]=dp[i][j-1]+1 , p[i][j]=-3 , --->p[i][j-1]4.dp[i][j]=dp[i][k]+dp[k+1][j] , p[i][ 阅读全文
posted @ 2013-03-02 23:46 Titanium 阅读(473) 评论(0) 推荐(0)
摘要:动态规划也是经典题目,黑书上也有介绍。今晚上JAVA在想,想了一下想出来,需要五维,大矩形的值由小矩形得到,这个状态转移方程个人感觉还是比较想到,但是一些细节的地方还没想到怎么处理,回来瞄一眼黑书得到了标准差的一个转化公式,所以疑团解开,便开始打代码(看黑书过程中它写的状态转移方程和我想的一样,但是有一些细微的细节,我感觉我这样处理比较保险,我后来细想了一下它的,虽然没有判断但是可能也不会出错,但是更倾向于我自己想的那种,就是关于横着切和竖着切的范围)忘记搞掉注释WA了一次,搞掉后就AC了,算是 一次成型不用debug,后来上网找报告,大家几乎都是用double来开数组的,其实不用double 阅读全文
posted @ 2013-02-27 23:41 Titanium 阅读(1787) 评论(0) 推荐(2)
摘要:状态压缩DP(使用位运算加速)这是个经典的状态压缩DP,为加深印象详细写写一下报告,由于是中文题目所以不说题意了思考方法:首先,一个炮的攻击有两行,所以对于第i行来讲,i-1行和i-2行对它有影响,i-3行及以上的都没有影响了,所以我们要得到第i行的信息,只需要知道i-1和i-2的信息(最近有个体会,DP要找到什么因素影响了当前你要求的东西,有影响的我们就处理,没影响的我们不用管)。接着我们就思考怎么表示状态。山用1表示,空地用0表示,空地放了兵也用1表示,那么对于一行,就是一个01的串,这是个二进制数,我们可以想到状态压缩压缩回来一个十进制数。比如原地图01101011,那么0处可以放兵,所 阅读全文
posted @ 2013-02-27 15:27 Titanium 阅读(3333) 评论(2) 推荐(2)
摘要:DP经典问题,石子合并描述:在一个圆形操场的四周摆放着n 堆石子。现要将石子有次序地合并成一堆。规定每次只能选相邻的2 堆石子合并成新的一堆,并将新的一堆石子数记为该次合并的得分。试设计一个算法,计算出将n堆石子合并成一堆的最小得分和最大得分。/*石子合并问题由于石子是未成一圈,所以首先我们要把圆圈剪断变成一条直线,而这样的直线有n条(每个石子都可以作为直线的开头)接下来我们就考虑直线的石子合并问题,这个其实就是矩阵链乘法dp[i][j]=min{ dp[i][k]+dp[k+1][j]+cost } cost为本次合并带来的代价,cost=ai+ai+1+ai+2……aj*/#include 阅读全文
posted @ 2013-02-25 16:31 Titanium 阅读(1122) 评论(0) 推荐(0)
摘要:DP(经典题):字符串最短编辑距离关于计算最短编辑距离的资料有很多,这里不详说,这题还要求输出路径,并且注意到是实时的输出,关键在于输出中的那个数字,即位置代码中已经有详细分析/*dp[i][j]表示a串前i个字符和b串前j个字符的最短编辑距离1.dp[i][j]=dp[i-1][j]+1 即先删除a串的第i个字符,然后使其前i-1个字符与b串的前j个字符相同2.dp[i][j]=dp[i][j-1]+1 即先让a串的前i个字符和b串的前j-1个字符相同,然后再在a串后面插入b[j]这个字符3.dp[i][j]=dp[i-1][j-1]+(a[i]==b[j]?0:1) 即先让a串前i-1.. 阅读全文
posted @ 2013-02-25 15:25 Titanium 阅读(755) 评论(0) 推荐(0)
摘要:DP(DAG最长路)题意:给出x轴上的线段的端点坐标,一个线段能覆盖另一个线段(端点不能相同),求出最多的线段覆盖并且从短到长给出路径。转化模型为DAG,求DAG上的最长路并且打印路径,用记忆化搜索实现#include <cstdio>#include <cstring>#define N 550int a[N],b[N],n;bool g[N][N];int dp[N],path[N];void dfs(int i){ if(dp[i]!=-1) return ; dp[i]=1; for(int j=1; j<=n; j++) if(g[i][j]) { .. 阅读全文
posted @ 2013-02-05 12:08 Titanium 阅读(264) 评论(0) 推荐(0)
摘要:DP(解码)题意:给出一个串的长度n,串只有0,1组成,但是不能有两个相邻的1。按字典序给串排列,最先肯定是0000,接着是0001,依此类推。给一个数字m,输出在长度为n的情况下,第m个排列的串是什么,如果m大于总排列数,输出-1这其实是一个解码的过程,必须用高位到低位解码(从左到右),因为这里要求字典序,字典序的比较水从左到右的由于数据规模固定在串长度44以内,所以我们先dp出所有长度下可能的排列数,编码时也要用每次编码按位编码,判断当前位为0还是为1,就是看填0或1可能产生多少排列数然后和m比较,这个看代码大概都能懂的#include <cstdio>#include < 阅读全文
posted @ 2013-02-05 09:54 Titanium 阅读(553) 评论(3) 推荐(0)
摘要:数学递推(DP)题意:有n个人,身高各不相同排成一列。从前面 看过去能看到p个人,后后面看过去能看到r个人。矮的人会被高的人挡着看不到。问满足p,r的情况下,有多少种排列的可能。/*DPdp[i][j][k]表示队列中有i个人,从前面可以看到j个人,后面可以看到k个人有多少种可能策略:从空队列开始,往其中插入人,从最高到最低插入,每次插入有3种位置,一种在队首,则从前面看的人数会加1,一种在队尾,则从队尾看的人数会加1,一种在中间(已经有n人在队中,那么有n-1个插入位置),则从队首和队尾看的人数 都不会增加状态转移方程 dp[i][j][k]=dp[i-1][j-1][k]+dp[i-1][ 阅读全文
posted @ 2013-01-28 17:17 Titanium 阅读(258) 评论(0) 推荐(0)
摘要:DP+高精度+滚动数组还是1009的题目,不过数据再大点,数组都开不下,需要滚动数组。回想1009的递推的方式,可以看到,要知道当前位的信息,只需要知道前一位的信息即可,所以其实任何时候都只需要两位,所以我们可能用户滚动数组,不断替换,而算法思想是完全不变的//用递推来实现,要得到当前位的信息只与前一位有关,因为用滚动数组,只保存两位,不断滚动//dp[0][]表示前一位的信息,dp[1][]表示当前位的信息,每一位的数字只能为0和非0#include <cstdio>#include <cstring>#define MAX 1900 //位数#define LEN 阅读全文
posted @ 2013-01-21 20:54 Titanium 阅读(397) 评论(0) 推荐(0)
摘要:DP+高精度 (和1009是一样的题目,不过数字的位数达到了180,所以要用高精度)同样是记忆化搜索实现,不过加入了高精度,一些细节地方就注意一下。我的代码写的不好,有点长有点乱…………#include <cstdio>#include <cstring>#define LEN 210 //高精度数组的大小#define MAX 210 //位数struct num{ int a[LEN],len; //a数组保存高精度}dp[MAX][15]; //最多180位,最高进制为10int N,K;void init(){ for(int i=1; i<N; i++) 阅读全文
posted @ 2013-01-21 17:40 Titanium 阅读(324) 评论(0) 推荐(0)
摘要:DP,最大子矩阵和:先按列压缩为一维i,在用最大连续子序列和来求。在枚举列压缩求和的时候,为了提高速度,可以在输入的时候先保存下来,就不用每次都去计算,不过再代码中没有写另外这题不允许空矩阵,即至少要有一个元素,所以代码要做稍微的修改,就这样WA了几次/*最大子矩阵和,先压缩为一维再求最大子序列和,时间复杂度O(n^3)*/#include <cstdio>#include <cstring>#define N 1100#define INF 0x3f3f3f3fint a[N][N],s[N],n;void get_sum(int x ,int y){ for(int 阅读全文
posted @ 2013-01-21 12:02 Titanium 阅读(345) 评论(0) 推荐(0)