题解:[NOIP2005 普及组] 采药
一道 0-1 背包模版题。
首先对于每株草药,只有两种情况:取或不取。那么我们就可以设一个数组(出于考虑有同学没学过动态规划,所以暂时不叫他 DP 状态),
这样我们就可以开始考虑如何得到
- 如果不取,那么就很简单,
f_{i,j} 还是等于f_{i-1,j} 。 - 如果取,这时候剩余的时间就会减少采这株采药所需的时间(
t_i ),但总价值就会加上这株草药的价值(v_i ),所以这时候f_{i,j} 就会等于f_{i-1,j-t_i}+v_i 。
考虑完两种情况后,我们只需要找他们两个中更优的方案,让
这样我们就可以得到代码了:
核心代码
for(int i = 1; i <= M; i++)
for(int j = 0; j <= T; j++)
f[i][j] = max(f[i-1][j], f[i-1][j-t[i]]+v[i]);
但是如果你这么交上去的话就会发现全都
其实我们仔细观察第 j-t[i]。这样是不是就发现问题了?如果
完整代码
#include <iostream>
using namespace std;
const int N = 1e3+5;
int t[N], v[N];
int f[105][N];
int main()
{
int T, M;
cin >> T >> M;
for(int i = 1; i <= M; i++)
cin >> t[i] >> v[i];
for(int i = 1; i <= M; i++)
for(int j = T; j >= 0; j--)
{
if(j >= t[i])
f[i][j] = max(f[i-1][j], f[i-1][j-t[i]]+v[i]);
else
f[i][j] = f[i-1][j];
}
cout << f[M][T] << endl;
return 0;
}
于是,我们就顺利通过此题了!
但是我们其实还可以将
如果大家有空间这个概念的话,就应该思考一个问题:如果题目中
首先来看,当我们处理到第
说的没错,仔细观察代码可以发现:当
AC Code
#include <iostream>
using namespace std;
const int N = 1e3+5;
int t[N], v[N];
int f[N];
int main()
{
int T, M;
cin >> T >> M;
for(int i = 1; i <= M; i++)
cin >> t[i] >> v[i];
for(int i = 1; i <= M; i++)
for(int j = T; j >= t[i]; j--)
f[j] = max(f[j], f[j-t[i]]+v[i]);
cout << f[T] << endl;
return 0;
}
是不是非常简短呢?
后记
其实背包问题不光只有 0-1 背包,还有完全背包、多重背包等变形问题。如果你还想学习这些问题,可以参考这里。
最后,希望这篇题解可以帮到你,祝你在 OI 的路上越走越远,慢慢喜欢上编程,获得更多成就!