动态规划:背包问题

 背包问题

背包问题是动态规划中最经典的问题,很多题⽬或多或少都有背包问题的影⼦。它的基本形式是:给 定⼀组物品,每个物品有体积和价值,在不超过背包容量的情况下,选择物品使得总价值最⼤。 背包问题有多种变体,主要包括:

1. 01背包问题:每种物品只能选或不选(选0次或1次)。

2. 完全背包问题:每种物品可以选择⽆限次。

3. 多重背包问题:每种物品有数量限制。

4. 分组背包问题:物品被分为若⼲组,每组只能选⼀个物品。

5. 混合背包:以上四种背包问题混在⼀起。

6. 多维费⽤的背包问题:限定条件不⽌有体积,还会有其他因素(⽐如重量)。 除了经典的总价值最⼤问题,还会有:

1. ⽅案总数。

2. 最优⽅案。

3. ⽅案可⾏性。

4. 输出具体⽅案。 因此,背包问题种类⾮常繁多,题型⾮常丰富。但是,尽管背包有很多变形,都是从01背包问题演化 过来的。所以,⼀定要把01背包问题学好。

1 .【模板】01背包

二维版本 

#include<iostream>
#include<cstring>
using namespace std;
const int N = 1010;
int n, m;
int w[N], v[N];//记录体积和价值和
int f[N][N];//在体积不超过j的情况下选了i中的最大价值

int main()
{
	cin >> n >> m;
	for (int i = 1; i <= n; i++)cin >> w[i] >> v[i];

	//问题一
	//初始化:第0行,在选0个物品的情况下,不超过体积,价值为0
	for (int i = 0; i <= m; i++)f[0][i] = 0;

	for (int i = 1; i <= n; i++)
	{
		for (int j = 0; j <= m; j++)//背包问题中体积是可以从0开始的
		{
			f[i][j] = f[i - 1][j];//没选的情况下,就和f[i-1][j]一样
			//选了
			if (j >= w[i])
			{
				f[i][j] = max(f[i][j],f[i - 1][j - w[i]] + v[i]);//在选和不选之中选择最大值
			}
		}
	}
	cout << f[n][m] << endl;
	//问题二,要求全部装满
	//初始化:第一行选择0个的条件下,不满足装满的条件,可以设置为负无穷大
	memset(f[0], -0x3f3f3f, sizeof(f[0]));
	f[0][0] = 0;//0 0 是满足条件de
	for (int i = 1; i <= n; i++)
	{
		for (int j = 0; j <= m; j++)
		{
			f[i][j] = f[i-1][j];
			if (j >= w[i])
			{
				f[i][j] = max(f[i][j], f[i-1][j - w[i]] + v[i]);
			}
		}
	}
	if (f[n][m] < 0)cout << 0 << endl;
	else
		cout << f[n][m] << endl;
	return 0;


}

第一问 

  不选

结果取最大值

 i可以从1到n,而j需要从0 到m

第二问 

 不合法的情况下,初始化成-∞,

这样就只需要判断结果f[n][m]是否为负数,是那么就找不到

不是,就有结果

空间优化版本

#include<iostream>
#include<cstring>
using namespace std;
const int N = 1010;
int n, m;
int w[N], v[N];//记录体积和价值和
int f[N];//在体积不超过j的情况下选了i中的最大价值

int main()
{
	cin >> n >> m;
	for (int i = 1; i <= n; i++)cin >> w[i] >> v[i];

	//问题一
	//初始化:第0行,在选0个物品的情况下,不超过体积,价值为0
	for (int i = 0; i <= m; i++)f[i] = 0;

	for (int i = 1; i <= n; i++)
	{
		for (int j = m; j >= w[i]; j--)//背包问题中体积是可以从0开始的
		{
			//选了
				f[j] = max(f[j],f[j - w[i]] + v[i]);//在选和不选之中选择最大值
		}
	}
	cout << f[m] << endl;
	//问题二,要求全部装满
	//初始化:第一行选择0个的条件下,不满足装满的条件,可以设置为负无穷大
	memset(f, -0x3f3f3f, sizeof(f));
	f[0] = 0;//0 0 是满足条件de
	for (int i = 1; i <= n; i++)
	{
		for (int j = m; j >= w[i]; j--)
		{
    		f[j] = max(f[j], f[j - w[i]] + v[i]);
		}
	}
	if (f[m] < 0)cout << 0 << endl;
	else
		cout << f[m] << endl;
	return 0;


}

(1)删掉第一维

(2)观察是否需要修改遍历顺序

2.P1048 [NOIP 2005 普及组] 采药 - 洛谷

#include<iostream>

using namespace std;
const int N = 1100;//时间超过1000,设置成100的哈,不符合
int t[N], v[N];
int f[N][N];//在不超过t时间的情况下,才n重要取得的最大价值
int main()
{
	int T, M; cin >> T >> M;
	for (int i = 1; i <= M; i++)cin >> t[i] >> v[i];

	//属于01背包的第一种问题,不需要初始化也可以
	for (int i = 1; i <= M; i++)
	{
		for (int j = 0; j <= T; j++)
		{
			f[i][j] = f[i - 1][j];
			if (j >= t[i])
			{
				f[i][j] = max(f[i][j], f[i - 1][j - t[i]] + v[i]);
			}
		}
	}
	cout << f[M][T] << endl;
	return 0;
}
//空间优化
#include<iostream>

using namespace std;
const int N = 1100;//时间超过1000,设置成100的哈,不符合
int t[N], v[N];
int f[N];//在不超过t时间的情况下,才n重要取得的最大价值
int main()
{
	int T, M; cin >> T >> M;
	for (int i = 1; i <= M; i++)cin >> t[i] >> v[i];

	//属于01背包的第一种问题,不需要初始化也可以
	for (int i = 1; i <= M; i++)
	{
		for (int j = T; j >= t[i]; j--)
		{
			if (j >= t[i])
			{
				f[j] = max(f[j], f[j - t[i]] + v[i]);
			}
		}
	}
	cout << f[T] << endl;
	return 0;
}

3.P1164 小A点菜 - 洛谷

#include<iostream>

using namespace std;

const int N = 110;//菜的种类
const int M = 1010;//多少钱
int v[N];
int n, m;
int f[N][M];//在正好用M元的情况下,点的n种菜,的方案数


int main()
{
	cin >> n >> m;
	for (int i = 1; i <= n; i++)cin >> v[i];

	//初始化,第一行中。
	f[0][0] = 1;//用0元买0菜,是一种方案,
	for (int i = 1; i <= n; i++)
	{
		for (int j = 0; j <= m; j++)
		{
			f[i][j] = f[i - 1][j];
			if (j >= v[i])
			{
				f[i][j] += f[i - 1][j - v[i]];
			}
		}
	}
	cout << f[n][m] << endl;
	return 0;
}

总方案数是两者累加在一起,而不是取最大值

有:就++

没有:那就不要了

 0 0 方案数为1

4.P2946 [USACO09MAR] Cow Frisbee Team S - 洛谷

 状态表示如果记录为能力值总和的话,会太大了

只需要记录取模运算为0 的即可。

 不选就找上面的

选,就找[j - a[i]]的,注意,这里会出现负数的情况,但在这道题中,负数也是有意义的。

比方说,我们要凑 j = 1,a[i] = 9, a[i]%5 == 4, j - a[i] = -3,我们本来是要找-3的位置的,使得取模 == 1但是我们是找不到的,但是我们可以反向的向前找2,4+2 == 6 ,取模 == 1。

取模运算

 初始化,0 0 ,结果要把 0 0 减去

#include<iostream>

using namespace std;
const int MOD = 1e8;
const int N = 2010;
const int M = 1010;
int n, m;//马的数量和幸运值
int v[N];//能力值
int f[N][M];//前1~i个马中,选出的能力值总和模幸运值的方案数

int main()
{
	cin >> n >> m;
	for (int i = 1; i <= n; i++)cin >> v[i];

	//初始化
	f[0][0] = 1;//选0个马,得出的能力值模幸运值为0
	for (int i = 1; i <= n; i++)
	{
		for (int j = 0; j < m; j++)
		{
			f[i][j] = (f[i - 1][j] + f[i - 1][((j - v[i]) % m + m) % m]) % MOD;
		}
	}
	cout << f[n][0] - 1 << endl;//把 0 0 减去
	return 0;
}

2. 完全背包问题

2.1【模板】完全背包

 

 根据f[i][j]的例子推导出下面的式子:f[i][j-v[i]];

然后用f[i][j-b[i]]+w[i]替代max的第二部分!!!!!!!!

 同01背包问题简直一模一样

二维化版本 
#include<iostream>
#include<cstring>
using namespace std;
const int N = 1010;

int f[N][N];
int n, m;
int w[N], v[N];

int main()
{
	cin >> n >> m;
	for (int i = 1; i <= n; i++)cin >> w[i] >> v[i];

	for (int i = 1; i <= n; i++)
	{
		for (int j = 0; j <= m; j++)
		{
			f[i][j] = f[i - 1][j];
			if (j >= w[i])
			{
				f[i][j] = max(f[i][j], f[i][j - w[i]] + v[i]);
			}
		}
	}
	cout << f[n][m] << endl;
	//初始化
	memset(f[0], -0x3f3f3f3f, sizeof(f[0]));
	f[0][0] = 0;
	for (int i = 1; i <= n; i++)
	{
		for (int j = 0; j <= m; j++)
		{
			f[i][j] = f[i - 1][j];
			if (j >= w[i])
			{
				f[i][j] = max(f[i][j], f[i][j - w[i]] + v[i]);
			}
		}
	}
	if (f[n][m] < 0)cout << 0 << endl;
	else cout << f[n][m] << endl;

}
空间优化版本 

#include<iostream>
#include<cstring>
using namespace std;
const int N = 1010;

int f[N];
int n, m;
int w[N], v[N];

int main()
{
	cin >> n >> m;
	for (int i = 1; i <= n; i++)cin >> w[i] >> v[i];

	for (int i = 1; i <= n; i++)
	{
		for (int j = w[i]; j <= m; j++)
		{
			f[j] = max(f[j], f[j - w[i]] + v[i]);
		}
	}
	cout << f[m] << endl;
	//初始化
	memset(f, -0x3f3f3f3f, sizeof(f));
	f[0] = 0;
	for (int i = 1; i <= n; i++)
	{
		for (int j = w[i]; j <= m; j++)
		{
			f[j] = max(f[j], f[j - w[i]] + v[i]);
		}
	}
	if (f[m] < 0)cout << 0 << endl;
	else cout << f[m] << endl;

}

2.2记录详情 - 洛谷 | 计算机科学教育新生态

#include<iostream>

using namespace std;

typedef long long LL;//算一下总价值达到了10^11,太大了,要用LL
const int T = 1e7 + 10;
const int N = 1e4 + 10;
int n, m;//种类,时间
int t[N], v[N];
LL f[T];//数组太大,空间优化,

int main()
{
	//空间优化版本
	cin >> m >> n;
	for (int i = 1; i <= n; i++)cin >> t[i] >> v[i];
	for (int i = 1; i <= n; i++)
	{
		for (int j = t[i]; j <= m; j++)
		{
			f[j] = max(f[j], f[j - t[i]] + v[i]);
		}
	}
	cout << f[m] << endl;
}

2.3P2918 [USACO08NOV] Buying Hay S - 洛谷

#include<iostream>
#include<cstring>
using namespace std;

const int N = 110;
const int M = 50010;
int p[N], c[N];
int f[N][M];
int n, m;

int main()
{
	cin >> n >> m;
	for (int i = 1; i <= n; i++)cin >> p[i] >> c[i];
	//初始化
	memset(f[0], 0x3f3f3f3f, sizeof(f[0]));
	f[0][0] = 0;
	for (int i = 1; i <= n; i++)
	{
		for (int j = 0; j <= m; j++)
		{
				f[i][j] = min(f[i-1][j], f[i][max(0, j - p[i])] + c[i]);
		}
	}
	cout << f[n][m] << endl;

	return 0;
}

 维持>=t的条件是以,刚好为基础,只不过加上了可以超过但置为下标0 的条件

。设置无穷大,用max(0 , f[][])来设防

2.4P5662 [CSP-J2019] 纪念品 - 洛谷

 

 股票问题:都可以转化成某天卖,隔天卖的过程

股票问题中的重要结论:
任何一笔跨天的交易,都可以转化成“某天买,隔天卖”的形式

不用考虑:某天买,那天卖?呢

连续,不要断开。

连续两天的交易情况,一定要连续。不可以断开。
 

 转化成背包问题,在金币不超过m的情况的;f[[i][j]记录的是最大利润

记得返回的时候是利润+本钱

#include<iostream>
#include<cstring>
using namespace std;

const int N = 110;
const int M = 10100;
int t, n, m;
int f[N][M];//在金币不超过m的情况的;f[[i][j]记录的是最大利润
int p[N][N];//记录某天的商品价格

int solve(int w[], int v[], int m)
{
	memset(f, 0, sizeof(f));//记得初始化
	for (int i = 1; i <= n; i++)
	{
		for (int j = 0; j <= m; j++)
		{
			f[i][j] = f[i - 1][j];//不买
			if (j >= w[i])//卖
			{
				f[i][j] = max(f[i][j], f[i][j - w[i]] + v[i] - w[i]);//花的钱+对应的利润
			}
		}
	}
	return f[n][m]+m;//返回本钱加利润
}

int main()
{
	cin >> t >> n >> m;
	for (int i = 1; i <= t; i++)
	{
		for (int j = 1; j <= n;j++)
		{
			cin >> p[i][j];
		}
	}
	for (int i = 1; i < t; i++)
	{
		//股票的结论任何一笔跨天的交易,都可以转化成“某天买,隔天卖”的形式

		//不用考虑:某天买,那天卖,直接连续不间断的买卖,有利润就卖,没利润就留着
		m = solve(p[i], p[i + 1], m);
	}
	cout << m << endl;
	return 0;

}

 3.多重背包问题

3.1多重背包

这里看着像是完全背包,但其实并不能像完全背包的方法进行优化。

因为完全背包是可以取无限个,最后的k1 实际上是可以等于 k2的。

但多重背包就不行,由于是有限个的,就肯能,导致,不能让替代成功。所以说不行

但是可以使用二进制进行优化

#include<iostream>

using namespace std;

const int N = 110;

int n, t;//物品种类和承重
int x[N], w[N], v[N];//物品数量,重量,价值
int f[N][N];//【1,i】之间,总重量buchaoguo t的条件下,的最大价值

int main()
{
	cin >> n >> t;
	for (int i = 1; i <= n; i++)cin >> x[i] >> w[i] >> v[i];

	//完全背包问题的实现
	for (int i = 1; i <= n; i++)
	{
		for (int j = 0; j <= t; j++)
		{
            f[i][j] = f[i - 1][j];
			for (int k = 0; k <= x[i]; k++)//做不了优化,只能全部拿出来一个一个地试
			{
				if (j >= k * w[i])
					f[i][j] = max(f[i][j], f[i - 1][j - k * w[i]] + k * v[i]);
                else break;
			}
		}
	}
	cout << f[n][t] << endl;
	return 0;
}
空间优化
#include<iostream>

using namespace std;

const int N = 110;

int n, t;//物品种类和承重
int x[N], w[N], v[N];//物品数量,重量,价值
int f[N];//【1,i】之间,总重量buchaoguo t的条件下,的最大价值

int main()
{
	cin >> n >> t;
	for (int i = 1; i <= n; i++)cin >> x[i] >> w[i] >> v[i];

	//完全背包问题的实现
	for (int i = 1; i <= n; i++)
	{
		for (int j = t; j >= 0; j--)
		{
			for (int k = 0; k <= x[i]; k++)//做不了优化,只能全部拿出来一个一个地试
			{
				if (j >= k * w[i])
					f[j] = max(f[j], f[j - k * w[i]] + k * v[i]);
                else break;
			}
		}
	}
	cout << f[t] << endl;
	return 0;
}
二进制优化

多重背包问题的二级制优化:可以把多重背包转化成01背包。

n*m*x ---> n*m*logx

!!!二进制优化不是万能的,求最大数可以使用,求方案数就不能使用。

#include <iostream>

using namespace std;

const int N = 110 * 5;

int n, m;

int w[N], v[N], pos;

int f[N];

int main()
{
	cin >> n >> m;
	for (int i = 1; i <= n; i++)
	{
		int x, y, z; cin >> x >> y >> z;
		// 按照⼆进制拆分 
		int t = 1;
		while (x >= t)
		{
			pos++;
			w[pos] = t * y;
			v[pos] = t * z;
			x -= t;
			t *= 2;
		}
		if (x) // 处理剩余 
		{
			pos++;
			w[pos] = x * y;
			v[pos] = x * z;
		}
	}

	// 针对拆分之后的物品,做⼀次 01背包即可 
	for (int i = 1; i <= pos; i++)
		for (int j = m; j >= w[i]; j--)
			f[j] = max(f[j], f[j - w[i]] + v[i]);
	cout << f[m] << endl;

	return 0;
}

3.2P1077 [NOIP 2012 普及组] 摆花 - 洛谷

#include<iostream>

using namespace std;
int n, m;
const int N = 1010;
const int Mod = 1e6 + 7;
int a[N];
int f[N][N];

int main()
{
	cin >> n >> m;
	for (int i = 1; i <= n; i++)cin >> a[i];

	f[0][0] = 1;
	for (int i = 1; i <= n; i++)
	{
		for (int j = 0; j <= m; j++)
		{
			f[i][j] = f[i - 1][j];//不选,把这一步写出来,不要省略
			for (int k = 1; k <= a[i]; k++)//选
			{
				if (j >= k)
				{
					f[i][j] = (f[i][j] + f[i - 1][j - k]) % Mod;//累加取模
				}
				else
				{
					break;
				}
			}
		}
	}
	cout << f[n][m] << endl;
	return 0;
}
空间优化
#include<iostream>

using namespace std;
int n, m;
const int N = 1010;
const int Mod = 1e6 + 7;
int a[N];
int f[N];

int main()
{
	cin >> n >> m;
	for (int i = 1; i <= n; i++)cin >> a[i];

	f[0] = 1;
	for (int i = 1; i <= n; i++)
	{
		for (int j = m; j >= 0; j--)
		{
			for (int k = 1; k <= a[i]; k++)//选
			{
				if (j >= k)
				{
					f[j] = (f[j] + f[j - k]) % Mod;//累加取模
				}
				else
				{
					break;
				}
			}
		}
	}
	cout << f[m] << endl;
	return 0;
}

4.分组背包

4.1P1757 通天之分组背包 - 洛谷

#include<iostream>
#include<vector>
using namespace std;

typedef pair<int, int> PII;
const int N = 1e3 + 10;
int n, m;//输入组数,承重
vector<PII> g[N];//这个数据结构感觉很重要的,g[N]记录有多少组,里面用PII记录重量和价值
int f[N][N];//[1,i]组内,不超过m的情况下,最大价值

int main()
{
	cin >> m >> n;
	int cnt = 0;//找组数
	for (int i = 1; i <= n; i++)
	{
		int a, b, c; cin >> a >> b >> c;
		cnt = max(cnt, c);
		g[c].push_back({ a,b });//是几号,就对应接到对应的几号上去
	}
	for (int i = 1; i <= cnt; i++)
	{
		for (int j = 0; j <= m; j++)
		{
			f[i][j] = f[i - 1][j];
			for (auto& x : g[i])
			{
				int a = x.first, b = x.second;
				if (j >= a)
				{
					f[i][j] = max(f[i][j], f[i - 1][j - a] + b);
				}
			}
		}
	}
	cout << f[cnt][m] << endl;
	return 0;
}

4.2P5322 [BJOI2019] 排兵布阵 - 洛谷

 

#include<iostream>
#include<algorithm>
using namespace std;
const int N = 110,M = 2e4+10;
int s, n, m;
int a[N][N];
int f[N][M];

int main()
{
	cin >> s >> n >> m;
	for(int i = 1;i <= s;i++)//玩家数
		for (int j = 1; j <= n; j++)//城池数
		{
			cin >> a[j][i];//反着存
			//贪心
			a[j][i] = 2 * a[j][i] + 1;//两倍+1可以拿下,先记录下,后遍历,拿到就攻下来
		}
	//排序
	for (int i = 1; i <= n; i++)
		sort(a[i]+1, a[i] + s + 1);//每个城池存着 s个玩家的派兵人数,对他们进行排序
	for (int i = 1; i <= n; i++)//城池
	{
		for (int j = 0; j <= m; j++)//手里的士兵
		{
			f[i][j] = f[i - 1][j];//不要
			for (int k = 1; k <= s; k++)//要
			{
				if (j >= a[i][k])
				{
					f[i][j] = max(f[i][j], f[i - 1][j - a[i][k]] + k * i);
				}
			}
		}
	}
	cout << f[n][m] << endl;
	return 0;
}

 5.混合背包

P1833 樱花 - 洛谷

//二维形式
#include<iostream>

using namespace std;

const int N = 1e4 + 10;
const int M = 1e3 + 10;

int ts_h, ts_m, te_h, te_m;
char s1, s2;
int n;
int t[N], c[N], p[N];
int f[N][M];

int main()
{
	cin >> ts_h >> s1 >> ts_m >> te_h >> s2 >> te_m;
	int time = te_h * 60 + te_m - ts_h * 60 - ts_m;
	cin >> n;
	for (int i = 1; i <= n; i++)cin >> t[i] >> c[i] >> p[i];

	for (int i = 1; i <= n; i++)
	{
		if (p[i] == 1)//01背包
		{
			for (int j = 0; j <= time; j++)
			{
				f[i][j] = f[i - 1][j];
				if (j >= t[i])
				{
					f[i][j] = max(f[i][j], f[i - 1][j - t[i]] + c[i]);
				}
			}
		}
		else if (p[i] == 0)//完全背包问题
		{
			for (int j = 0; j <= time; j++)
			{
				f[i][j] = f[i - 1][j];
				if(j >= t[i])
				f[i][j] = max(f[i - 1][j], f[i][j - t[i]] + c[i]);
			}
		}
		else//多重背包问题
		{
			for (int j = 0; j <= time; j++)
			{
				f[i][j] = f[i - 1][j];
				for (int k = 1; k <= p[i]; k++)
				{
					if (j >= k * t[i])
					{
						f[i][j] = max(f[i][j], f[i - 1][j - k * t[i]] + k * c[i]);
					}
				}
			}
		}
	}
	cout << f[n][time] << endl;
	return 0;
}
//优化形式
//#include<iostream>
//
//using namespace std;
//
//const int N = 1e4 + 10;
//const int M = 1e3 + 10;
//
//int ts_h, ts_m, te_h, te_m;
//char s1, s2;
//int n;
//int t[N], c[N], p[N];
//int f[M];
//
//int main()
//{
//	cin >> ts_h >> s1 >> ts_m >> te_h >> s2 >> te_m;
//	int time = te_h * 60 + te_m - ts_h * 60 - ts_m;
//	cin >> n;
//	for (int i = 1; i <= n; i++)cin >> t[i] >> c[i] >> p[i];
//
//	for (int i = 1; i <= n; i++)
//	{
//		if (p[i] == 1)//01背包
//		{
//			for (int j = time; j >= t[i]; j--)//大到小
//			{
//				
//				f[j] = max(f[j], f[j - t[i]] + c[i]);
//				
//			}
//		}
//		else if (p[i] == 0)//完全背包问题
//		{
//			for (int j = t[i]; j <= time; j++)//小到大
//			{
//					f[j] = max(f[j], f[j - t[i]] + c[i]);
//			}
//		}
//		else//多重背包问题
//		{
//			for (int j = time; j >= t[i]; j--)
//			{
//				for (int k = 1; k <= p[i]; k++)
//				{
//					if (j >= k * t[i])
//					{
//						f[j] = max(f[j], f[j - k * t[i]] + k * c[i]);
//					}
//				}
//			}
//		}
//	}
//	cout << f[time] << endl;
//	return 0;
//}

6.P1910 L 国的战斗之间谍 - 洛谷(多维背包)

相对于01背包只是多了个限制条件罢了 

第二个注意点如果不进行空间优化的话,会空间爆掉 100*1000*1000

//没有优化
// #include<iostream>
//
//using namespace std;
//
//const int N = 110, M = 1010;
//
//int a[N], b[N],c[N];
//int f[N][M][M];
//
//int n, m, x;
//int main()
//{
//	cin >> n >> m >> x;
//
//	for (int i = 1; i <= n; i++)cin >> a[i] >> b[i] >> c[i];
//
//
//	for (int i = 1; i <= n; i++)
//	{
//		for (int j = 0; j <= m; j++)
//		{
//			for (int k = 0; k <= x; k++)
//			{
//				f[i][j][k] = f[i - 1][j][k];
//				if (j >= b[i] && k >= c[i])
//				{
//					f[i][j][k] = max(f[i][j][k], f[i - 1][j - b[i]][k - c[i]]+a[i]);
//				}
//			}
//		}
//	}
//	cout << f[n][m][x] << endl;
//	return 0;
//}
//空间优化
#include<iostream>

using namespace std;

const int N = 110, M = 1010;

int a[N], b[N], c[N];
int f[M][M];

int n, m, x;
int main()
{
	cin >> n >> m >> x;

	for (int i = 1; i <= n; i++)cin >> a[i] >> b[i] >> c[i];


	for (int i = 1; i <= n; i++)
	{
		for (int j = m; j >= b[i]; j--)
		{
			for (int k = x; k >= c[i]; k--)
			{
				if (j >= b[i] && k >= c[i])
				{
					f[j][k] = max(f[j][k], f[j - b[i]][k - c[i]] + a[i]);
				}
			}
		}
	}
	cout << f[m][x] << endl;
	return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值