标准的一维背包:NOIP2005普及组第三题 采药
大概的题目描述:山洞里有一些不同的草药,采每一株都需要一些时间,每一株也有它自身的价值。给你一段时间,在这段时间里,可以采到一些草药。让采到的草药的总价值最大。
输入格式:
第一行有2个整数T(1≤T≤1000)和M(1≤M≤100),用一个空格隔开,T代表总共能够用来采药的时间,M代表山洞里的草药的数目。
接下来的M行每行包括两个在1到100之间(包括1和100)的整数a和b,分别表示采摘某株草药的时间和这株草药的价值。
输出格式:
1个整数,表示在规定的时间内可以采到的草药的最大总价值。
选 或者 不选当前的草药进行采摘
先枚举每种采药
再倒着枚举时间【重点是找到来源,所以要倒着。而且每种草药只有一个,如果正着枚举无法确定这一点并会搜到自己留下的痕迹的影响,例:如果正着枚举,a = 2, (b不重要)枚举到s[1](s是dp数组)时会标记s[2],但是在枚举到s[2]时又会进行标记】
选的时候:
上一个状态s[j - a]保留的最大值 + 当前枚举到的草药的价值 > 当前状态保留的最大值
(反之不选)
#include <bits/stdc++.h>
using namespace std;
int s[1500] = {}; //背包,默认最大值都是零
int main()
{
int n, m;
int i, j;
int a, b;
cin >> n >> m;
for (i = 1; i <= m; i++)
{
cin >> a >> b;
for (j = n; j >= a; j--)
s[j] = max(s[j], s[j - a] + b);
}
cout << s[n] << endl;
return 0;
}
二维背包
具体的枚举过程与一维背包很像,也是选或者不选
只是要在枚举背包容量时是双重循环(二维)
例:洛谷 P1855 榨取kkksc03
https://www.luogu.org/problemnew/show/P1855
#include <bits/stdc++.h>
using namespace std;
int s[220][220];
int main()
{
int n, m, t;
int i, j, k;
int a, b;
cin >> n >> m >> t;
memset(s, 0, sizeof(s));
for (i = 1; i <= n; i++)
{
cin >> a >> b; //金钱,时间
for (j = m; j >= a; j--)
for (k = t; k >= b; k--)
s[j][k] = max(s[j - a][k - b] + 1, s[j][k]);
}
cout << s[m][t] << endl;
return 0;
}