《挑战程序设计竞赛》2.3 动态规划-基础 POJ3176 2229 2385 3616 3280
POJ3176
题意
输入一个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[n][j],最大的一个即为所求。
但其实用一维数组也能够完成要求,具体请看我的代码。
代码
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[N], dp[N];
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
题意
求把一个整数分解为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。所以一定要注意答案的范围。
代码
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[n]);
return 0;
}
POJ2385
题意
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。
代码
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
题意
奶牛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次产奶量。
代码
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
题意
有一个由n个小写字母组成的,长度为m的字符串,可以对其通过增加字符或者删除字符来使其变成回文。而增加或者删除字符都有一个花费,求解使该字符串变成回文的最小花费。
思路
动态规划。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']);
更详细的分析(以下内容转自小鱼的博客):
其实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的最小代价。
代码
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;
}
《挑战程序设计竞赛》2.3 动态规划-基础 POJ3176 2229 2385 3616 3280的更多相关文章
- 《挑战程序设计竞赛》2.3 动态规划-优化递推 POJ1742 3046 3181
POJ1742 http://poj.org/problem?id=1742 题意 有n种面额的硬币,面额个数分别为Ai.Ci,求最多能搭配出几种不超过m的金额? 思路 据说这是传说中的男人8题呢,对 ...
- Aizu 2249Road Construction 单源最短路变形《挑战程序设计竞赛》模板题
King Mercer is the king of ACM kingdom. There are one capital and some cities in his kingdom. Amazin ...
- 挑战程序设计竞赛》P345 观看计划
<挑战程序设计竞赛>P345 观看计划 题意:一周一共有M个单位的时间.一共有N部动画在每周si时 ...
- POJ 2386 Lake Counting 题解《挑战程序设计竞赛》
地址 http://poj.org/problem?id=2386 <挑战程序设计竞赛>习题 题目描述Description Due to recent rains, water has ...
- poj 3253 Fence Repair 贪心 最小堆 题解《挑战程序设计竞赛》
地址 http://poj.org/problem?id=3253 题解 本题是<挑战程序设计>一书的例题 根据树中描述 所有切割的代价 可以形成一颗二叉树 而最后的代价总和是与子节点和深 ...
- 《挑战程序设计竞赛》2.3 动态规划-进阶 POJ1065 1631 3666 2392 2184(5)
POJ1065: Description There is a pile of n wooden sticks. The length and weight of each stick are kno ...
- 《挑战程序设计竞赛》 4.1.1 矩阵 P286
想写几篇挑战的感悟,也有助于自己理解这本书.但这上面大多贴的是书上的代码,主要是为了用的时候后直接复制就好了,这样就很方便了,就相当于黑盒模板了. 1.线性方程组 /** \brief 高斯消元法 * ...
- 《挑战程序设计竞赛》P196 铺砖问题
题意:给定n*m格子,每个格子被染成了黑色或者白色,现在要用1*2的砖块覆盖这些格子,块与块不得重叠,且覆盖所有的白色格子,但不覆盖任意一个黑色格子,求一共有多少种覆盖方法. 思路:书上给的思路太巧妙 ...
- poj 1979 Red and Black 题解《挑战程序设计竞赛》
地址 http://poj.org/problem?id=1979 Description There is a rectangular room, covered with square tiles ...
随机推荐
- unity, StopAllCoroutines导致bug的解决办法
StopAllCoroutines有时候不用不行. 但只要一用,就可能导致无穷无尽的bug. 原因是StopAllCoroutines会将当前脚本中所有coroutines都停掉,而没法做到只停掉我们 ...
- Sublime Text 2 和 Verilog HDL
Sublime Text 2 和 Verilog HDL Date Fri 04 July 2014 Tags Sublime Text / Vivado Sublime Text 代码编辑器之于程 ...
- RCU
RCU(read-copy-update)同步机制.R(Read):读者不需要获得任何锁就可访问RCU保护的临界区:C(Copy):写者在访问临界区时,写者“自己”将先拷贝一个临界区副本,然后对副本进 ...
- SPI—读写串行 FLASH
SPI协议简介SPI 协议是由摩托罗拉公司提出的通讯协议(Serial Peripheral Interface),即串行外围设备接口,是一种高速全双工的通信总线.它被广泛地使用在 ADC. LCD ...
- string 大小写转换
STL的algorithm库确实给我们提供了这样的便利,使用模板函数transform可以轻松解决这个问题,开发人员只需要提供一个函数对象,例如将char转成大写的toupper函数或者小写的函数 ...
- Yii2 Restful API 原理分析
Yii2 有个很重要的特性是对 Restful API的默认支持, 通过短短的几个配置就可以实现简单的对现有Model的RESTful API 参考另一篇文章: http://www.cnblogs. ...
- 【Mac + Appium + Python3.6学习(四)】之常用的IOS自动化测试API总结
环境: Appium:1.9.1 Appium-desktop:1.7.1 Xcode:10.0 IOS:iPhone5S(10.3.3) Mac:10.13.6 ①获取手机屏幕size:长.宽 &l ...
- RMAN 总括 组成 配置 检测
RMAN 组件: 1. RMAN 执行程序, 也就是RMAN 命令. 2. Server session : 服务器上的进程, 是真正用来干活的. 3. Target database: 你想要进行备 ...
- 用Eclipse的tomcat插件启动tomcat时报错:
用Eclipse的tomcat插件启动tomcat时报错: FATAL ERROR in native method: JDWP No transports initialized, jvmtiErr ...
- easyui menu 添加hideItem/showItem 方法
$.extend($.fn.menu.methods,{ showItem:function(jq,text){ return jq.each(function(){ var item = $(thi ...