《挑战程序设计竞赛》2.3.1 动态规划-基础 POJ3176 2229 2385 3616 3280
2015-12-19 16:04
471 查看
POJ3176
Cow Bowling题意
输入一个n层的三角形,第i层有i个数,求从第1层到第n层的所有路线中,权值之和最大的路线。规定:第i层的某个数只能连线走到第i+1层中与它位置相邻的两个数中的一个。
思路
最显而易见的是使用二维数组动态规划计算。比如dp[i][j]表示以第i行j列的位置作为终点的路线的最大权值。 (注意区分初始化时的意义)
那么dp[i][j]的最大值取决于dp[i-1][j-1]和dp[i-1][j],从这两者之间筛选出最大值,加到dp[i][j]上,即为dp[i][j]的最大权值。
最后只要比较第n行中所有位置的权值dp
[j],最大的一个即为所求。
但其实用一维数组也能够完成要求,具体请看我的代码。
代码
[code]Source Code Problem: 3176 User: liangrx06 Memory: 248K Time: 79MS Language: C++ Result: Accepted Source Code #include <iostream> #include <cstdio> #include <algorithm> using namespace std; const int N = 350; int main(void) { int n; int a , dp ; cin >> n; dp[0] = 0; for (int i = 0; i < n; i ++) { for (int j = 0; j <= i; j ++) { scanf("%d", &a[j]); } for (int j = i; j >= 0; j --) { if (j == 0) dp[j] = dp[j] + a[j]; else if (j == i) dp[j] = dp[j-1] + a[j]; else dp[j] = max(dp[j], dp[j-1]) + a[j]; } } int sum = 0; for (int i = 0; i < n; i ++) sum = max(dp[i], sum); printf("%d\n", sum); return 0; }
POJ2229
Sumsets题意
求把一个整数分解为2的幂的和共有几种方案。例如整数7的分解有6种方案:
7=1+1+1+1+1+1+1
7=1+1+1+1+1+2
7=1+1+1+2+2
7=1+1+1+4
7=1+2+2+2
7=1+2+4
思路
这种题通常都是用递归来解的。假设n对应的分解方案数为f(n)首先按照n为奇数和偶数的情况分别分析:n为奇数时,分解式中一定含有1,去掉这个1,剩下的分解式的和为n-1,也就是说,f(n) = f(n-1);
n为偶数时,分解式中若含有1,方案数为f(n-1),若不含有1,将分解式中的数都除以2,其和对应于n/2,也就是说方案数为f(n/2),所以f(n) = f(n-1)+f(n/2)。
如此由n=1的初始条件递归求解即可,也可以说是动态规划。
但是这个题我WA了三次,后来发现这个题的答案会超出long long的表示范围,需要取余,改了好几次才AC。所以一定要注意答案的范围。
代码
[code]Source Code Problem: 2229 User: liangrx06 Memory: 4136K Time: 125MS Language: C++ Result: Accepted Source Code #include <iostream> #include <cstdio> #include <algorithm> using namespace std; const int N = 1000000; int main(void) { int n; int a[N+1]; cin >> n; a[0] = 1; for (int i = 1; i <= n; i ++) { if (i&1) a[i] = a[i-1]; else a[i] = a[i/2] + a[i-1]; a[i] %= 1000000000; } printf("%lld\n", a ); return 0; }
POJ2385
Apple Catching题意
2棵苹果树在T分钟内随机由某一棵苹果树掉下一个苹果,奶牛站在树#1下等着吃苹果,它最多愿意移动W次,问它最多能吃到几个苹果。思路
动态规划题。状态空间主要决定于W,以dp[i][j][k]表示第i+1分的时候经过j次移动站在了k+1树下能吃到的最大苹果数,然后搜索所有的ijk组合,更新dp。实际上我使用的数组是dp[i&1][j][k],用i&1的目的是降低空间复杂度,dp数组大小降为原来的2/T。
代码
[code]Source Code Problem: 2385 User: liangrx06 Memory: 248K Time: 16MS Language: C++ Result: Accepted Source Code #include <iostream> #include <cstdio> #include <cstring> #include <algorithm> using namespace std; const int T = 1000; const int W = 30; int main(void) { int t, w; int a[T+1]; int dp[2][W+1][2]; cin >> t >> w; memset(dp, 0, sizeof(dp)); for (int i = 1; i <= t; i ++) { scanf("%d", &a[i]); a[i] --; for (int j = 0; j <= w; j ++) { dp[i&1][j][a[i]] = dp[(i-1)&1][j][a[i]] + 1; dp[i&1][j][(a[i]+1)&1] = dp[(i-1)&1][j][(a[i]+1)&1]; if (j > 0) { dp[i&1][j][a[i]] = max(dp[i&1][j][a[i]], dp[(i-1)&1][j-1][(a[i]+1)&1] + 1); dp[i&1][j][(a[i]+1)&1] = max(dp[i&1][j][(a[i]+1)&1], dp[(i-1)&1][j-1][a[i]]); } } } int res = 0; for (int j = 0; j <= W; j ++) { res = max(res, dp[t&1][j][0]); res = max(res, dp[t&1][j][1]); } printf("%d\n", res); return 0; }
POJ3616
Milking Time题意
奶牛Bessie在0~N时间段产奶。农夫约翰有M个时间段可以挤奶,时间段f,t内Bessie能挤到的牛奶量e。奶牛产奶后需要休息R小时才能继续下一次产奶,求Bessie最大的挤奶量。思路
定义dp[i]表示第i个时间段(注意此处的第i个时间段不等同于第i次)挤奶能够得到的最大值,拆开来说,就是前面 i – 1个时间段任取0到i – 1个时间段挤奶,然后加上这个时间段(i)的产奶量之和。dp[i]满足如下递推关系:
第i个时间段挤奶的最大值 = 前 i – 1 个时间段挤奶的最大值的最大值 + 第i次产奶量。
代码
[code]Source Code Problem: 3616 User: liangrx06 Memory: 184K Time: 0MS Language: C++ Result: Accepted Source Code #include <iostream> #include <cstdio> #include <algorithm> using namespace std; const int M = 1000; struct Time { int f, e, v; }; bool cmp(const Time& a, const Time& b) { return a.f < b.f; } int main(void) { int n, m, r; Time t[M]; int dp[M+1]; int ans = 0; scanf("%d%d%d", &n, &m, &r); for (int i = 0; i < m; i ++) scanf("%d%d%d", &t[i].f, &t[i].e, &t[i].v); sort(t, t+m, cmp); memset(dp, 0, sizeof(dp)); for (int i = 0; i < m; i ++) { dp[i] = t[i].v; for (int j = 0; j < i; j ++) { if (t[i].f >= t[j].e + r) dp[i] = max(dp[i], dp[j] + t[i].v); } ans = max(ans, dp[i]); } printf("%d\n", ans); return 0; }
POJ3280
Cheapest Palindrome题意
[code]有一个由n个小写字母组成的,长度为m的字符串,可以对其通过增加字符或者删除字符来使其变成回文。而增加或者删除字符都有一个花费,求解使该字符串变成回文的最小花费。
思路
[code]动态规划。dp[i][j]表示串str[i~j]变成回文的最小代价,故状态转移方程为: 当str[i] == str[j]时 dp[i][j] = dp[i+1][j-1]; 当str[i] != str[j]时 dp[i][j] = min( dp[i+1][j]+add[str[i]-'a'], dp[i][j-1]+add[str[j]-'a'], dp[i+1][j]+del[str[i]-'a'], dp[i][j-1]+del[str[j]-'a']);
更详细的分析(以下内容转自小鱼的博客):
[code]其实dp很难逃出3种思路: 1、一维线性dp:每次考虑i时,选择最优子问题要么在i-1,要么在1...i-1里; 2、二维线性dp:考虑(i,j)子问题时,选择最优子问题要么在(i+1,j)、(i,j-1),要么在i<= k <=j,在k里; 3、树形dp:考虑i节点最优时,选择子节点最优,一般融合了01背包dp的双重dp。 上面3种模式也是我在做题后才发现的。 这个dp题其实就可以仿照第2中思路。 假设一个字符串Xx....yY;对于求这个字符串怎么求呢? 分4种情况讨论: 1、去掉X,取x....yY回文; 2、去掉Y,取Xx....y回文; 3、在左边加上X,取Xx....yYX回文; 4、在右边加上Y,取YXx....y回文。 至于去掉X、Y肯定没有第1、2中情况合算;加上X、Y肯定没有第3、4中情况合算。 因此令dp[i][j]为i...j要变成回文字符串的最小代价。 方程: dp[i][j] = min{ dp[i+1][j] + {去掉X的代价},dp[i+1][j] + {加上X的代价},dp[i][j-1]+ {去掉Y的代价},dp[i][j-1] +{加上Y的代价}}; 其实分析发现,对于X而言,只要去 去掉 和加上 X 最小代价就行(因为前面dp串一样),Y同理。 因此最后得出: dp[i][j] = min{ dp[i+1][j] +min{ {去掉X的代价}, {加上X的代价}},dp[i][j-1]+min{ {去掉Y的代价}, {加上Y的代价}}}; dp时候还有些注意事项: 比如当X和Y字符一样时,则在dp时必须先为x...y的最小代价。
代码
[code]Source Code Problem: 3280 User: liangrx06 Memory: 15852K Time: 172MS Language: C++ Result: Accepted Source Code #include <iostream> #include <cstdio> #include <cstring> #include <algorithm> using namespace std; const int M = 2000; int dp[M+1][M+1]; int main(void) { int i, j, k, n, m; char s[M+1]; int add[26], del[26]; scanf("%d%d%s", &n, &m, s); for (i = 0; i < n; i ++) { char c[2]; scanf("%s", c); scanf("%d", &add[c[0]-'a']); scanf("%d", &del[c[0]-'a']); } memset(dp, 0, sizeof(dp)); for (k = 0; k < m; k ++) { for (i = 0; i < m-k; i ++) { j = i + k; if (s[i] == s[j]) dp[i][j] = dp[i+1][j-1]; else { dp[i][j] = min(dp[i+1][j] + add[s[i]-'a'], dp[i+1][j] + del[s[i]-'a']); dp[i][j] = min(dp[i][j], dp[i][j-1] + add[s[j]-'a']); dp[i][j] = min(dp[i][j], dp[i][j-1] + del[s[j]-'a']); } } } printf("%d\n", dp[0][m-1]); return 0; }
相关文章推荐
- 直线光栅画法
- ubuntu14.04默认sshd配置不允许root登录,scp命令执行有问题
- Cocos2dx 中CCAssert 断言操作的使用。
- 《挑战程序设计竞赛》2.3 动态规划-基础 POJ3176 2229 2385 3616 3280
- GHOSTXPSP3电脑爱好者V9.9装机版
- a399 调试·传值·错误数字
- Unity3D手游开发日记(2) - 技能系统架构设计
- Android之Fragment学习(二)
- 微机接口双色点阵-- 变化的表情动画
- c#面向对象中static 关键字
- Beta版本冲刺总结
- Logistic Regression(逻辑斯特回归)
- 10021---display(显示)
- android项目Tab标签页面大汇总(Fragment、Fragment+ViewPage、TabLayout)
- ios 项目中 用到的动画
- Phoenix使用总结
- 模型操作语句--note
- Cloudera hadoop-2.3.0-cdh5.1.0 在Centos 6.5 下的安装
- Drupal7网站+IIS7.0+PHP+MySql
- 抽象工厂模式(head first读书笔记)