今天学习动态规划
有两个经典例题:
1,最长公共子序列问题
2,最长不下降序列问题
然后就是题单:
1,洛谷 p1192[台阶问题]
# 台阶问题
## 题目描述
有 N级台阶,你一开始在底部,每次可以向上迈 k级台阶,问到达第 N级台阶有多少种不同方式。
## 输入格式
两个正整数 $N,K$。
## 输出格式
一个正整数 ans\pmod{100003},为到达第 $N$ 级台阶的不同方式数。
## 样例 #1
### 样例输入 #1
```
5 2
```
### 样例输出 #1
8
提示
- 对于 20% 的数据,$1\leq N\leq10$,$1\leq K\leq3$;
- 对于 40% 的数据,$1\leq N\leq1000$;
- 对于 100% 的数据,$1\leq N\leq100000$,$1\leq K\leq100$。
这道题先试着写一下案例,然后联想dp的思想,就会发现大概是一个斐波那契的算法。
注意令a【0】=1;
#define _CRT_SECURE_NO_WARNINGS 1
#include <iostream>
#include<cstring>
#include<algorithm>
using namespace std;
int main() {
int n, k;
scanf("%d %d", &n, &k);
long long a[100005] = { 0 };
a[0] = 1;
a[1] = 1;
for (int i = 2; i <= n; i++) {
for (int j = 1; j <= k; j++) {
if(i - j >= 0) {
a[i] += a[i - j];
a[i]=a[i] % 100003;
//注意这里数据比较大,必须时刻模100003;不然最后输出会变成0;
}
}
}
printf("%lld\n", a[n]%100003);
}
2,洛谷 p1216【数字三角形】
# [USACO1.5] [IOI1994]数字三角形 Number Triangles
## 题目描述
观察下面的数字金字塔。
写一个程序来查找从最高点到底部任意处结束的路径,使路径经过数字的和最大。每一步可以走到左下方的点也可以到达右下方的点。
![](https://cdn.luogu.com.cn/upload/image_hosting/95pzs0ne.png)
在上面的样例中,从 $7 \to 3 \to 8 \to 7 \to 5$ 的路径产生了最大权值。
## 输入格式
第一个行一个正整数 $r$ ,表示行的数目。
后面每行为这个数字金字塔特定行包含的整数。
## 输出格式
单独的一行,包含那个可能得到的最大的和。
## 样例 #1
### 样例输入 #1
```
5
7
3 8
8 1 0
2 7 4 4
4 5 2 6 5
```
### 样例输出 #1
```
30
```
## 提示
【数据范围】
对于 $100\%$ 的数据,$1\le r \le 1000$,所有输入在 $[0,100]$ 范围内。
题目翻译来自NOCOW。
USACO Training Section 1.5
IOI1994 Day1T1
比较简单的一道题;
注意2维数组要开在全局,1005*1005局部储存不了;
#define _CRT_SECURE_NO_WARNINGS 1
#include <iostream>
#include<cstring>
#include<algorithm>
using namespace std;
int a[1005][1005] = { 0 };
int main() {
int n;
scanf("%d", &n);
for (int i = 1; i <= n; i++) {
for (int j = 1; j <= i; j++) {
scanf("%d", &a[i][j]);
}
}
for (int i = n - 1; i >= 1; i--) {
for (int j = 1; j <= i + 1; j++) {
a[i][j] += max(a[i + 1][j], a[i + 1][j + 1]);
}
}
printf("%d", a[1][1]);
}
这道题如果从上到下写要用sort进行排序;注意sort是左闭右开(a[n]+1,a[n]+1+n);
3,洛谷1048【采药】
# [NOIP2005 普及组] 采药
## 题目描述
辰辰是个天资聪颖的孩子,他的梦想是成为世界上最伟大的医师。为此,他想拜附近最有威望的医师为师。医师为了判断他的资质,给他出了一个难题。医师把他带到一个到处都是草药的山洞里对他说:“孩子,这个山洞里有一些不同的草药,采每一株都需要一些时间,每一株也有它自身的价值。我会给你一段时间,在这段时间里,你可以采到一些草药。如果你是一个聪明的孩子,你应该可以让采到的草药的总价值最大。”
如果你是辰辰,你能完成这个任务吗?
## 输入格式
第一行有 $2$ 个整数 $T$($1 \le T \le 1000$)和 $M$($1 \le M \le 100$),用一个空格隔开,$T$ 代表总共能够用来采药的时间,$M$ 代表山洞里的草药的数目。
接下来的 $M$ 行每行包括两个在 $1$ 到 $100$ 之间(包括 $1$ 和 $100$)的整数,分别表示采摘某株草药的时间和这株草药的价值。
## 输出格式
输出在规定的时间内可以采到的草药的最大总价值。
## 样例 #1
### 样例输入 #1
```
70 3
71 100
69 1
1 2
```
### 样例输出 #1
```
3
```
## 提示
**【数据范围】**
- 对于 $30\%$ 的数据,$M \le 10$;
- 对于全部的数据,$M \le 100$。
**【题目来源】**
NOIP 2005 普及组第三题
这道题目运用了0-1背包,一维dp的思想,绝对不可以用贪心搞;
#define _CRT_SECURE_NO_WARNINGS 1
#include <iostream>
#include<cstring>
#include<algorithm>
using namespace std;
int t, m, a[105], b[105];
int f[1005] = {0};
int main() {
scanf("%d %d", &t, &m);
for (int i = 1; i <= m; i++) {
scanf("%d %d", &a[i], &b[i]);
}
for (int i = 1; i <= m; i++) {
for (int j = t; j >= a[i]; j--) {
f[j] = max(f[j - a[i]] + b[i], f[j]);
}
}
printf("%d", f[t]);
}
从第一个开始,计算出从f(t)到f(1)的最优情况,每跳动一组数都重新计算一遍;
从上往下,从右往左走;
状态转移方程:dp(i,j)=max(dp(i-1,j),dp(i-1,j-w(i)+v(i));
4,洛谷 p1616【疯狂地采药】
# 疯狂的采药
## 题目背景
此题为纪念 LiYuxiang 而生。
## 题目描述
LiYuxiang 是个天资聪颖的孩子,他的梦想是成为世界上最伟大的医师。为此,他想拜附近最有威望的医师为师。医师为了判断他的资质,给他出了一个难题。医师把他带到一个到处都是草药的山洞里对他说:“孩子,这个山洞里有一些不同种类的草药,采每一种都需要一些时间,每一种也有它自身的价值。我会给你一段时间,在这段时间里,你可以采到一些草药。如果你是一个聪明的孩子,你应该可以让采到的草药的总价值最大。”
如果你是 LiYuxiang,你能完成这个任务吗?
此题和原题的不同点:
$1$. 每种草药可以无限制地疯狂采摘。
$2$. 药的种类眼花缭乱,采药时间好长好长啊!师傅等得菊花都谢了!
## 输入格式
输入第一行有两个整数,分别代表总共能够用来采药的时间 $t$ 和代表山洞里的草药的数目 $m$。
第 $2$ 到第 $(m + 1)$ 行,每行两个整数,第 $(i + 1)$ 行的整数 $a_i, b_i$ 分别表示采摘第 $i$ 种草药的时间和该草药的价值。
## 输出格式
输出一行,这一行只包含一个整数,表示在规定的时间内,可以采到的草药的最大总价值。
## 样例 #1
### 样例输入 #1
```
70 3
71 100
69 1
1 2
```
### 样例输出 #1
```
140
```
## 提示
#### 数据规模与约定
- 对于 $30\%$ 的数据,保证 $m \le 10^3$ 。
- 对于 $100\%$ 的数据,保证 $1 \leq m \le 10^4$,$1 \leq t \leq 10^7$,且 $1 \leq m \times t \leq 10^7$,$1 \leq a_i, b_i \leq 10^4$。
这道题是完全背包,要从左往右写,这样可以重复取药;
注意数据范围long long;
#define _CRT_SECURE_NO_WARNINGS 1
#include <iostream>
#include<cstring>
#include<algorithm>
using namespace std;
long long t, m, a[10005], b[10005];
long long f[10000005] = { 0 };
int main() {
scanf("%lld %lld", &t, &m);
for (int i = 1; i <= m; i++) {
scanf("%lld %lld", &a[i], &b[i]);
}
for (int i = 1; i <= m; i++) {
for (int j = a[i]; j<=t; j++) {
f[j] = max(f[j - a[i]] + b[i], f[j]);
}
}
printf("%lld", f[t]);
}