随笔分类 -  动态规划

摘要:学过简单动态规划的人应该对最长公共子序列的问题很熟悉了,这道题只不过多加了一条字符串变成三条了,还记得,只要把状态变成三维的即可。//http://lightoj.com/volume_showproblem.php?problem=1159//2013-08-15-09.50#include #include #include #include using namespace std;char str1[55];char str2[55];char str3[55];int dp[55][55][55];int maxval(int a, int b, int c){ a = max(... 阅读全文
posted @ 2013-08-15 15:20 xindoo 阅读(171) 评论(0) 推荐(0)
摘要://hdoj 3555//2013-06-27-16.53#include #include __int64 dp[21][3], n;int len, bit[21];//dp[i][0] 长度为i 包含49的个数//dp[i][1] 长度为i没有49但以9开头的//dp[i][2] 长度为i 没有49void init(){ dp[0][2] = 1; for (int i = 1; i 4) ans += dp[i-1][1]; if (bit[i] == 9 && bit[i+1] == 4) ... 阅读全文
posted @ 2013-06-27 17:00 xindoo 阅读(151) 评论(0) 推荐(0)
摘要:这题数据量相对比较小,可以暴力打表解决。不过我这里用数位dp 刚开始学数位dp,参考了别人的代码。//2013-06-27-15.30#include #include int dp[7][3];//dp[i][0] 表示不存在不吉利的数字//dp[i][1] 表示不存在不吉利的数字,且最高位是2//dp[i][2] 表示存在不吉利的数字int bit[10];void init(){ dp[0][0] = 1; for (int i = 1; i 4) //高位可能出现4的情况 ans += dp[i-1][0]; if (!flag &... 阅读全文
posted @ 2013-06-27 15:42 xindoo 阅读(172) 评论(0) 推荐(0)
摘要:http://poj.org/problem?id=1664 这题可以用递归的方式做,想给第一个盘子里放上苹果从(0到m),然后给第二个放上,为了保证每次产生的放法是不同的,第二个里面放置的苹果不能从0开始,否则就会产生相同的放法,然后同理第三第四个盘子。。。。 还有一个问题,可能放到最后一个盘子了,还有很多苹果没有放,怎么办?? 都放最后一个里面?? 其实不是,这样的话可能和前面某种情况出发,所以在放置的过程中就要保证不能产生这种情况,(y/(n-x) >= i)这行代码就保证了,因为盘子里面的苹果数是非递减的,剩余i个盘子,只要剩余的苹果数除以剩余的盘子数不小于当前盘子的苹果数,就可 阅读全文
posted @ 2013-06-27 14:49 xindoo 阅读(208) 评论(0) 推荐(0)
摘要:http://poj.org/problem?id=1050 我们已经知道求最大子段和的dp算法 参考 here 也可参考编程之美有关最大子矩阵和部分。 然后将这个扩大到二维就是这道题。顺便说一下,有时候不要把问题想复杂了,有些问题只能靠暴力求解,而这道题是暴力加算法。 在这个题中,我们可以把二维压缩到一维然后求解最大子段。我们先枚举所求矩阵的起点行和结束行,然后把每一列的数据之和求出,用这些数据和就构造出一个一维的数组(代码中我没有明确表示出这个数组),然后用最大子段和的dp算法求解。 关于二维压缩到一维的过程,适当处理可以大大减小时间复杂度。 最终时间复杂度是O(n^3);... 阅读全文
posted @ 2013-06-26 10:33 xindoo 阅读(240) 评论(0) 推荐(0)
摘要: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]+w,f[i-1,j]); 3.线性动态规划1-----朴素最长非降子序列F = 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);6.剖分问题3------乘积最大f[i,j] = max(f[k,j-1]*mult[k 阅读全文
posted @ 2013-06-03 10:19 xindoo 阅读(2201) 评论(0) 推荐(2)
摘要:大概题意就是求最少添加多少个字符可以把长度为N的字符串编程回文串。则需要最少需要补充的字母数 = 原序列S的长度 — S和S'的最长公共子串长度S'为原串的逆串。关于求最长公共子串, 用到的是动态规划伪代码如下if( i ==0 || j == 0 ){ MaxLen(i, j) = 0 //两个空串的最长公共子序列长度当然是0}else if( s1[i] == s2[j] ) MaxLen(i, j) = MaxLen(i-1, j-1 ) + 1;else { MaxLen(i, j) = Max( MaxLen(i, j-1), MaxLen(i-1, j));}具体. 阅读全文
posted @ 2013-05-30 20:08 xindoo 阅读(142) 评论(0) 推荐(0)
摘要:题目链接详细请参考刘汝佳《算法竞赛入门经典训练指南》 p67//2013-05-01-20.40//uva 10891#include #include #include using namespace std;const int maxn = 105;bool vis[maxn][maxn];int s[maxn];int d[maxn][maxn];int dp(int i, int j){ if (vis[i][j]) return d[i][j]; vis[i][j] = true; int m = 0; for (int k = i+1; k <... 阅读全文
posted @ 2013-05-27 20:56 xindoo 阅读(144) 评论(0) 推荐(0)
摘要:题目链接//2013-05-17-21.08#include #include #include using namespace std;const int maxn = 100004;int dp[maxn][12];int main(){ int n, maxt, t, x; int tmax; while(scanf("%d", &n) && n) { memset(dp, 0, sizeof(dp)); maxt = 0; for (int i = 0; i = 0; t--) { f... 阅读全文
posted @ 2013-05-17 21:06 xindoo 阅读(217) 评论(0) 推荐(0)
摘要:题目链接 如果你是刚刚开始做状态压缩dp,我建议你先看看 poj 3254 Corn Fields 这是一道比这一题更简单,更容易入门的题目。 还有在代码中我用了一个很巧妙的方法求一个数二进制数中1的个数 具体请看我博客中 x& (x - 1)==0这篇文章 链接。 还有一点,不同于poj 3254的地方,我们不能直接枚举所有的状态。我在getresult()中用到了四重循环,直接枚举的时间复杂度是2^40,并且dp那个数组也是开不下到,不过对于这道题还是有方法的。枚举一行所有的状态,行合法(没有两个1相隔少于两个)的状态总共有61中,我们只需要枚举所有合法状态即可,循环次数最多是61 阅读全文
posted @ 2013-05-08 20:16 xindoo 阅读(144) 评论(0) 推荐(0)
摘要:题目链接题意:Farmer John 放牧cow,有些草地上的草是不能吃的,用0表示,然后规定两头牛不能相邻放牧。问你有多少种放牧方法。 状态压缩dp其实就是用二进制来表示所有的状态,比如这题, 我们在某一行可以这样取0 1 0 1 1 0 1,用1代表取了,0代表没取,因为这点,它的数据量也限制在20以内,所有看到这样数据量的题目可以先考虑一下状态压缩dp。对于有多行的数据,所有状态的总数必然很庞大,而且不用特殊的方法想要存储这些状态是不太现实的。既然每个点只有这两种情况,我们可以用二进制的一位来表示,0 1 0 1 1 0 1就可以表示为二进制0101101也就是十进制的45,如果我们.. 阅读全文
posted @ 2013-05-07 20:21 xindoo 阅读(178) 评论(0) 推荐(0)
摘要:题目链接题意:在一个n*n的棋盘上放m个车,使得各个车之间不相互攻击。有多少种放法?组合数学解法 现在n行中选出m行,C(n,m),再在n列中选出m列随便放A(n,m),答案为C(n,m)*A(n,m)。#include #include typedef __int64 LL;LL A(int n, int m){ LL ans = 1; for (int i = n-m+1; i <= n; i++) ans *= i; return ans;}LL C(int n, int m){ LL ans = 1; for (int i = 1; i <=... 阅读全文
posted @ 2013-05-06 20:28 xindoo 阅读(141) 评论(0) 推荐(0)
摘要:题目链接题意: 题目的大概意思是把数组分成不交两段,分别求出两段的最大子段和s1和s2,然后求出最大的s1+s2。不知道最大子段和的点这 here思路: 看完最大连续子段和 的 dp算法这个很容易理解,我用dplift[i]保存第1到第i个之间的最大子段和,dpright[i]保存第i到第n个之间的最大子段和,最终结果就是dplift[i]+dpright[i+1]中最大的一个。代码//poj 2479 Maximum sum//2013-05-01-17.26#include #include #include using namespace std;const int maxn =... 阅读全文
posted @ 2013-05-01 17:47 xindoo 阅读(165) 评论(0) 推荐(0)
摘要:问题描述: 有n个数(以下都视为整数,浮点的也一样),每个数有正有负,现在要在n个数中选取相邻的一段,使其和最大,输出最大的和。问题分析: 对于这样的问题,我们可以直接用暴力,一个双重循环,虽说可以,但也没有更高明的方法? 我们再分析这个问题,如果我们知道了某个数前面一段数的和,我们就该考虑把这个数加入到前一段,还是重新开始一段。这个地方很重要,如果前一段的和小于0,我们重新建一段,反之加到前一段。这样我们就可以把n个数分成几段了,且每一段都求出了他们的和,然后再循环一次求出最大的一个和,我们就得到想要的结果了,也可以在分段的时候直接求结果。代码int MaxSub (int a[]){ .. 阅读全文
posted @ 2013-05-01 17:32 xindoo 阅读(224) 评论(0) 推荐(0)
摘要:题目链接题意 有个小球,只能向右边或下边滚动,而且它下一步滚动的步数是它在当前点上的数字,如果是0表示进入一个死胡同。求它从左上角到右下角到路径数目。注意, 题目给了提示了,要用64位的整数。记忆化搜索方法#include #include #define ll __int64int n;ll vis[36][36];char board[36][36];ll dfs(int x,int y){ if(x==n-1&&y==n-1) return 1; if(board[x][y]=='0') return 0; if(vis[x][y]) ... 阅读全文
posted @ 2013-04-29 14:24 xindoo 阅读(168) 评论(0) 推荐(0)