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[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

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。所以一定要注意答案的范围。

代码

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

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。

代码

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次产奶量。

代码

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

题意

有一个由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的更多相关文章

  1. 《挑战程序设计竞赛》2.3 动态规划-优化递推 POJ1742 3046 3181

    POJ1742 http://poj.org/problem?id=1742 题意 有n种面额的硬币,面额个数分别为Ai.Ci,求最多能搭配出几种不超过m的金额? 思路 据说这是传说中的男人8题呢,对 ...

  2. Aizu 2249Road Construction 单源最短路变形《挑战程序设计竞赛》模板题

    King Mercer is the king of ACM kingdom. There are one capital and some cities in his kingdom. Amazin ...

  3. 挑战程序设计竞赛》P345 观看计划

                                                 <挑战程序设计竞赛>P345 观看计划 题意:一周一共有M个单位的时间.一共有N部动画在每周si时 ...

  4. POJ 2386 Lake Counting 题解《挑战程序设计竞赛》

    地址 http://poj.org/problem?id=2386 <挑战程序设计竞赛>习题 题目描述Description Due to recent rains, water has ...

  5. poj 3253 Fence Repair 贪心 最小堆 题解《挑战程序设计竞赛》

    地址 http://poj.org/problem?id=3253 题解 本题是<挑战程序设计>一书的例题 根据树中描述 所有切割的代价 可以形成一颗二叉树 而最后的代价总和是与子节点和深 ...

  6. 《挑战程序设计竞赛》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 ...

  7. 《挑战程序设计竞赛》 4.1.1 矩阵 P286

    想写几篇挑战的感悟,也有助于自己理解这本书.但这上面大多贴的是书上的代码,主要是为了用的时候后直接复制就好了,这样就很方便了,就相当于黑盒模板了. 1.线性方程组 /** \brief 高斯消元法 * ...

  8. 《挑战程序设计竞赛》P196 铺砖问题

    题意:给定n*m格子,每个格子被染成了黑色或者白色,现在要用1*2的砖块覆盖这些格子,块与块不得重叠,且覆盖所有的白色格子,但不覆盖任意一个黑色格子,求一共有多少种覆盖方法. 思路:书上给的思路太巧妙 ...

  9. poj 1979 Red and Black 题解《挑战程序设计竞赛》

    地址 http://poj.org/problem?id=1979 Description There is a rectangular room, covered with square tiles ...

随机推荐

  1. 关于JSP和HTML

    工作中,发现非常多同事不清楚JSP与HTML的生命周期.以至于出现"JavaScript为啥不能调用JSTL标签(或EL表达式)?"的笑话问题. 以下以流程图的方式.简单说明一下过 ...

  2. word2vector 理解入门

    1.什么是word2vector? 我们先来看一个问题,假如有一个句子 " the dog bark at the mailman". 假如用向量来表示每个单词,我们最先想到的是用 ...

  3. 在intellij中使用checkStyle进行代码规范

    1 编写代码检测规则可以参考阿里和google的规则和checkstyle的官网文档.checkstyle官网地址http://checkstyle.sourceforge.net/ 假设自己的sty ...

  4. Javascript网页截屏的方法

    最近我在研究开发一个火狐插件,具体的功能是将网页内容截屏并分享到微博上.目前基本功能已经实现,大家可以在 @程序师视野 里看到用这个截图插件分享的微博的效果. 之前我曾写过如何将canvas图形转换成 ...

  5. CCNA2.0笔记_NAT

    NAT:园区网内的PC是私有地址,整个园区网共享一个公有IP,如果园区网内的PC不做NAT,那么在发数据包给外网的时候会出现传输问题 NAT的原理:改变IP包头,使目的地址.源地址或两个地址在包头中被 ...

  6. c# 文件操作 txt、xml、ini

    1. txt文件 /// <summary> /// 读文本文件信息 /// </summary> /// <param name="FilePath" ...

  7. java 读写文件常用方法

    package study.bigdata; import org.apache.commons.io.FileUtils; import org.apache.commons.io.IOUtils; ...

  8. @override 报错问题

    Java的Eclipse工程换一台电脑后编译总是@override报错,把@override去掉就好了,但不能从根本上解决问题,因为有时候有@override的地方超级多. 这是jdk的问题,@Ove ...

  9. 成功抓取csdn阅读量过万博文

    http://images.cnblogs.com/cnblogs_com/elesos/1120632/o_111.png var commentscount = 1; 嵌套的评论算一条,这个可能有 ...

  10. windows下使用c++调用redis

    不废话,unix下c++调用 redis可以看这个: http://blog.csdn.net/youngqj/article/details/8266177 ==================== ...