【动态规划】一维背包和二维背包模板题 NOIP2005普及组 采药 + luogu P1855 榨取kkksc03

标准的一维背包: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 

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 

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;
}

 

你可能感兴趣的:(动态规划)