poj上的dp专题

更新中...node

http://poj.org/problem?id=1037ubuntu

dp[i][j][0]表示序列长度为i,以j开始而且前两位降低的合法序列数目;数组

dp[i][j][1]表示序列长度为i, 以j开始而且前两位上升的合法序列数目;优化

因而咱们能够获得递推方程式:dp[i][j][0] += dp[i-1][k][1] ( 1 <= k < j ), dp[i][j][1] += dp[i-1][k][0] ( k <= j <= i), 而后咱们就能够从第一位开始枚举了。spa

http://paste.ubuntu.com/6941791/code

 

http://poj.org/problem?id=1887blog

题目看了半天,就是求最长降低子序列,nlog(n)作法,不过莫名其妙的wa了好屡次,不能多说。。递归

http://paste.ubuntu.com/6952643/字符串

 

http://poj.org/problem?id=1157get

dp[i][j]表示前i束花放到前j个花瓶中所得到的最大价值,因而有dp[i][j] = max(dp[i-1][j-1] + value[i][j], dp[i][j-1]) (i <= j <= m)(这是由于对于第i束花,能够选择放在第j个花瓶中,也能够选择放在前j - 1个花瓶中)

稍微要注意一下的就是初始化的问题了,因为是有序的放,所以dp[i][i] = dp[i-1][i-1] + value[i][i](1 <= i <= n)

http://paste.ubuntu.com/6953048/

 

http://poj.org/problem?id=1088

这道题很容易就看出要用记忆化搜索,若是周围的点的高度比当前的点的高度要低,就dfs。

http://paste.ubuntu.com/6953207/

 

http://poj.org/problem?id=1014

多重背包的应用,很少说。

http://paste.ubuntu.com/6954121/

 

http://poj.org/problem?id=1160

dp[i][j]表示前i个邮局设立在前j个村庄的最短距离和,sum[i][j]表示第i个村庄到第j个村庄创建一个邮局的距离和,显然,该邮局创建在i,j的中点位置最佳,因而咱们能够得出:dp[i][j] = min(dp[i][j], dp[i-1][k] + sum[k + 1][j]) ( 1 <=k < j).而sum[i][j] = sum[i][j-1] + pos[j] - pos[(i + j) /2], 最后注意一下初始化就能够了。

http://paste.ubuntu.com/6957889/

 

http://poj.org/problem?id=1179

pair<long long, long long > dp[i][j]表示第i个数字到第j个数字通过运算后的最小值以及最大值,而后就须要枚举断开的位置了,而且因为是环,须要取模处理,最后就是记忆化搜索了,须要注意的就是两个最小值相乘也有可能成为最大值。

http://paste.ubuntu.com/6960005/

 

http://poj.org/problem?id=1141

记忆化搜索,dp[i][j]表示从第i个数字到第j个数字最少要插入的字符数,因而能够得出dp[i][j] = dp[i][k] + dp[k + 1][j](i <=k < j),而且当str[i] ==‘(’ && str[j] == ')' ||  str[i] == '[' && str[j] == ']'时,有dp[i][j] = dp[i + 1][j - 1];因为涉及到打印路径,须要开辟一个数组来记录每次选择的结果,而后递归求解。

http://paste.ubuntu.com/6964829/

 

http://poj.org/problem?id=1170

这道题要用到六进制压缩,若是第一种物品表示为state = 1,那么第二种物品表示为state = 6,而且以此类推,总状态就可表示为S = num1 * 1 + num2 * 6 + ...,而后就是用到彻底背包了, 设dp[state]表示状态为state时的最小的价格。

http://paste.ubuntu.com/6969768/

 

http://poj.org/problem?id=1191

刘汝佳黑书上的题目,p116.

记忆化搜索,dp[x1][y1][x2][y2][k]表示左上角(x1,y1) -> (x2, y2)的区域切割k块的最小值。

1 double ans = 1LL << 60;
2 for (int i = x1; i < x2; i++) {
3     ans = min(ans, dfs(x1, y1, i, y2, k - 1) + getSum(i + 1, y1, x2, y2));
4     ans = min(ans, dfs(i + 1, y1, x2, y2, k - 1) + getSum(x1, y1, i, y2));
5 }
6 for (int i = y1; i < y2; i++) {
7     ans = min(ans, dfs(x1, y1, x2, i, k - 1) + getSum(x1, i + 1, x2, y2));
8     ans = min(ans, dfs(x1, i + 1, x2, y2, k - 1) + getSum(x1, y1, x2, i));
9 }

http://paste.ubuntu.com/6970765/

 

http://poj.org/problem?id=1661

调一个BUG调了一个从下午一直调到如今,最后发现原来是有一处地方发生了溢出!这种低级错误之后必定要杜绝!仍是说说题目吧:

dp[i][0]表示从第i层的左端跳下所用的最短期,dp[i][1]表示从第i层的右端跳下所用的最短期,因而咱们经过能够判断端点的位置的关系得出递推方程。

http://paste.ubuntu.com/6975857/

 

http://poj.org/problem?id=1745

dp[i][j]表示对前i个数字进行操做计算后MOD % k后为j, 那么若是dp[i][j]为true,则dp[i + 1][(j + num[i + 1]) % K] 和 dp[i + 1][ ( j - num[i + 1]) % K]均为true.

http://paste.ubuntu.com/6976041/

 

http://poj.org/problem?id=1837

和上一题差很少,都须要加一个偏移量,这里我选择偏移量为7500(假设全部砝码都挂在最右,则最大力距为20*15*25),dp[i][j]表示挂了前i个砝码,力距为j的方案数,因而咱们能够得出:dp[i][j + pos[k] * g[i]] += dp[i - 1][j] ( 1 <= k <= C)。最后就是初始化的问题了,假设第一个砝码每一个位置都挂一遍,因而有dp[1][pos[i] * g[1] + 7500] = 1( 1 <= i <= C).

http://paste.ubuntu.com/6979698/

 

http://poj.org/problem?id=1836

一道不错的题目,咱们能够从左向右求一次最长上升子序列,从右向左求一次最长上升子序列,分别用Up数组和Down数组老保存,而后用dp1[i]表示1-i的最长上升序列长度,dp2[i]表示i-n的最长降低上升序列,而且用mark1[]和mark2[]数组来记录这个最长上升序列是否必需要包含i点,因而剩下的问题就直接枚举中间点就能够了。

http://paste.ubuntu.com/6980546/

 

http://poj.org/problem?id=1952

一道很不错的dp题,题目的意思是要求最长降低子序列的个数,这个很容易,可是有一个要求,就是若是两个最长降低子序列是同样的,就只能算一个,这个须要处理一下。

http://paste.ubuntu.com/6993356/

 

http://poj.org/problem?id=2137

dp[i][j][k]表示从第一头牛的j位置到第i头牛的k位置的最短距离,因而能够得出dp[i][j][k] = min(dp[i][j][k], dp[i-1][j][l] + getDist(k, l)),因为要围成圈,最后首位相连便可,须要注意初始化问题。

http://paste.ubuntu.com/6993710/

 

http://poj.org/problem?id=2184

dp[i][s]表示前i头奶牛聪明度为s是的最大的快乐度,这就相似与01背包的处理方法了,可是因为体积能够为负,这时咱们须要加一个偏移量,而且处理的时候从小到大进行处理.

http://paste.ubuntu.com/6997548/

 

http://poj.org/problem?id=2241

一块砖一共有6中摆放方式,dp[i]表示使用前i块砖所能达到的最大的高度,因而有dp[i] = max(dp[i], dp[j] + node[i].z) (0 <= j < i) 赋初值的时候要注意,当只放一块砖的时候,是每种状况均可以的(一开始没注意到,wa了好屡次)。

http://paste.ubuntu.com/6999070/

 

http://poj.org/problem?id=2264

本题的关键之处就是求出最长公共子序列而且用另一个数组来标记,而后就是递归输出最后的ans。

http://paste.ubuntu.com/6999927/

 

http://poj.org/problem?id=2353

dp[i][j]表示到第i层第j个房间的最小值,因而有dp[i][j] = min(dp[i- 1][j], dp[i][j - 1], dp[i][j + 1]) + num[i][j].而后分别从左向右dp和从右向左dp,同时记录路径就能够了,最后遍历最后一行找值最小的列,递归输出便可。

http://paste.ubuntu.com/7009043/

 

http://poj.org/problem?id=3612

dp[i][j]表示第i个高度为j时前i个的最小值,很容易想到这样一个递推关系式:dp[i][j] = min(dp[i-1][k] + abs(k-j) * C + (num[i] - j) * (num[i] - j));可毫无疑问,复杂度过高。。。只能想办法优化一下:

对于k >= j有:dp[i][j]=j*c+(a[i]-j)*(a[i]-j)+min(dp[i-1][k]-k*c) (1<=k<=j)

对于k < j 有:dp[i][j]=-j*c+(a[i]-j)*(a[i]-k)+min(dp[i-1][k]+k*c) (j<k<=m)

low[j]表示min(dp[i-1][k]-k*c)(1<=k<=j) high[j]=min(dp[i-1][k]+k*c)(j<k<=m)

因而能够预处理出这两个数组,在转移的时候就可以作到O(1)了,这样也就下降复杂度了。

http://paste.ubuntu.com/7009907/

 

http://poj.org/problem?id=2385

dp[i][0][j]表示到第i秒在1号树下返回j次的最大值,dp[i][1][j]表示到第i秒在2号树下返回j次的最大值。而后求一下递推关系便可。

http://paste.ubuntu.com/7010136/

 

http://poj.org/problem?id=2392

先按ai的值从小到大排,而后就是多重背包了。

http://paste.ubuntu.com/7010489/

 

http://poj.org/problem?id=2479

求两个不相交的连续子段的最大和,能够从左到右扫一遍,从右到左扫一遍而且分别用dp1[],dp2[]来记录,而后更新最大值便可。

http://paste.ubuntu.com/7014856/

 

http://poj.org/problem?id=2486

一道很不错的题目,dp[i][j][0]表示从节点i出发,能走j步,最后回到i点的最大值,dp[i][j][1]表示从i点出发走j步最后停留在i的某棵子树上点最大值,因而能够得出一下三种状况:

dp[0][s][j+2]=Max(dp[0][s][j+2],dp[0][t][k]+dp[0][s][j-k]);//从s出发,要回到s,须要多走两步s- >t,t- > s,分配给t子树k步,其余子树j-k步,都返回
dp[1][s][j+2]=Max(dp[1][s][j+2],dp[0][t][k]+dp[1][s][j-k]);//不回到s(去s的其余子树),在t子树返回,一样有多出两步
dp[1][s][j+1]=Max(dp[1][s][j+1],dp[1][t][k]+dp[0][s][j-k]);//先遍历s的其余子树,回到s,s - > t, 遍历t子树,在当前子树t不返回,多走一步.

http://paste.ubuntu.com/7015701/

 

http://poj.org/problem?id=2559

l[i]表示大于等于h[i]的最左边的位置,r[i]表示大于等于h[i]的最右边的位置,这样能够预处理出l[],r[],而后ans = max(ans, r[i] - l[i] + 1) * h[i])( 1 <= i  <= n).

http://paste.ubuntu.com/7016077/

 

http://poj.org/problem?id=2663

先把3行n列转成n行3列,dp[row][state]表示第i行状态为state的总数,因而dp[row][s2] += dp[row - 1][s1] 其中s1,s2两状态合法,这题与poj2411几乎同样。

http://paste.ubuntu.com/7016354/

 

http://poj.org/problem?id=2817

状态压缩,dp[state][i]表示当前状态为state,而且以第i个字符串开头的最大匹配数,这里的状态须要解释一下,指的是用到了那几个字符串。因而咱们能够获得递推关系:

dp[state | (1 << j] = min(dp[state | (1 << j)], dp[state][i] + num[i][j]),其中num[i][j]指的是字符串i和字符串j的最大匹配数。

http://paste.ubuntu.com/7026396/

 

http://poj.org/problem?id=2923

状态压缩,首先预处理出哪些物品可以被两辆车一块儿带走,dp[state]表示当前为状态为state下所须要的最小的次数。而后就是赤裸裸的状压dp了。

http://paste.ubuntu.com/7026803/

 

http://poj.org/problem?id=3036

首先把六边型映射到直角坐标,对于点(x,y),可以走的6个点分别为:(x, y - 1), (x, y + 1), (x - 1, y), (x + 1, y), (x + 1, y - 1), (x - 1, y + 1)。

dp[step][x][y]表示当前在点(x,y),已经走了step步的方法数,因为走的时候坐标可能为负,因而总体平移,令(15,15)为坐标原点,dp[0][15][15] =1,那么最后要求的不就是dp[n][15][15]了。

http://paste.ubuntu.com/7030831/

 

http://poj.org/problem?id=3042

区间dp,dp[i][j][0]表示i到j之间已经走过,而且如今在i点的最小值,dp[i][j][1]表示如今在j点,因而对于在i点,可能从i +1 - > i, 也可能从j - i,即:

dp[i][j][0] = min(dp[i + 1][j][0]  + (n - (j - i) ) * (pos[i + 1] - pos[i]), dp[i + 1][j][1] + (n - (j - i)) * (pos[j] - pos[i]));

同理对于当前在j点,也能够获得向相应的方程:dp[i][j][1] = min(dp[i][j-1][1] + (n - (j - i)) * (pos[j] - pos[j - 1), dp[i][j - 1][0] + (n - (j - i)) * (pos[j] - pos[i])).

而后须要注意的就是初始话的问题了,找到L在原序列中的位置。

http://paste.ubuntu.com/7031972/

 

http://poj.org/problem?id=3046

dp[i][j]表示用前i中类型组成序列长度为j的方法数,因而就有dp[i][j] += dp[i - 1][j - k] (0 <= k <= num[i]).

能够优化的地方,采用滚动数组,不过每次都必须清空,一开始没这么干,样例都过不了。

http://paste.ubuntu.com/7032709/

 

http://poj.org/problem?id=3132

dp[i][j]表示用j个素数获得和为n的方案数,这就相似与01背包了。

状态转移方程:dp[i][j] += dp[i - x][j - 1](其中x为素数);

http://paste.ubuntu.com/

 

http://poj.org/problem?id=3140

dp[u]表示以u为根的全部子树的和,则有ans = min(ans, (sum - dp[u]) - dp[u]).在dfs的过程当中不断更新便可。

http://paste.ubuntu.com/7036461/

 

http://poj.org/problem?id=1185

dp[i][j][k]表示第i行状态为j,第i - 1行状态为k的最大可放置数量.

首先预处理出可行的状态,即相邻的两个1之间的距离至少要大于2。

而后就是状压dp搞搞了.dp[i][j][k] = max(dp[i][j][k], dp[i-1][k][l] + num[i])(j, k, l状态不冲突,num[i]为第i行此时可以放的个数).

http://paste.ubuntu.com/7059384/

 

http://poj.org/problem?id=2288

dp[i][j][s]表示当前点为j,上一点是i,当前状态为s下的最小值;

ways[i][j][s]表示当前点为j,上一点为i,当前状态为s下的相同最小值的个数.

注意一下初始化。

http://paste.ubuntu.com/7060817/

相关文章
相关标签/搜索