01背包问题(转载自B站)

【0-1背包问题】手撕代码_哔哩哔哩_bilibili

二维数组构成以及回溯

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

const int MAXN = 10010;		//定义最大物品的数量
const int MAXV = 10010;		//定义最大背包的容量
int	N;		//储存物品数量
int V;		//定义背包的容量
int w[MAXN];	//	储存每件物品的重量w[i]
int c[MAXV];		//储存每件物品的价值c[i]
int dp[MAXN][MAXV];	//二维dp数组
vector<int> choose;		//定义存储方案(用于回溯)
void knapsack()
{
	//边界处理
	for (int i = 0; i <= V; i++)
		dp[0][i] = 0;
	//状态更新
	for (int i = 1; i <= N; i++)
		for (int v = 0; v <= V; v++)
		{
			if (v >= w[i])
				dp[i][v] = max(c[i] + dp[i - 1][v - w[i]], dp[i - 1][v]);	//能放得下第i件物品
			else dp[i][v] = dp[i - 1][v];		//放不下第i件物品
		}
}
//回溯
void flashback()
{
	int i = N, j = V;
	while (j != 0)		//因为是从最大的开始回溯,什么时候截止呢?在j=0或i=0时截止,j=0时,是没有容量了,i=0时是没有物品了
	{
		if (dp[i][j] == dp[i - 1][j])		//情况1:没有选择第i件物品
			i--;
		else {
			choose.push_back(i);		//情况2:选择了第i件物品
			j = j - w[i];
			i--;
		}
	}
}
int main()
{
	cin >> N >> V;		//输入物品个数和最大的背包容量
	for (int i = 1; i <= N; i++)
		cin >> w[i];
	for (int i = 1; i <= N; i++)
		cin >> c[i];
	knapsack();
	flashback();		//回溯
	cout << endl << dp[N][V] << endl;	//输出最大值
	for (int i = choose.size() - 1; i >= 0; i--)		//因为vector先存的是编号大的数,现在要把编号从小到大输出,就让vector反着输出
		cout << choose[i] << " ";

	return 0;
}
/*
输入数据:
5 8 
3 5 1 2 2 
4 5 2 1 3
*/

先从最大(dp[5][8])倒着往前推,如果dp[5][8]==dp[4][8]则回到dp[4][8]否则回到dp[4][8-2]即dp[4][6]然后同理继续往前推,直到j=0或i=0时结束,j=0时,是没有容量了,i=0时是没有物品了

滚动数组优化:(滚动数组由于1维,无法回溯但优化了空间复杂度)

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

const int MAXN = 10010;		//定义最大物品的数量
const int MAXV = 10010;		//定义最大背包的容量
int	N;		//储存物品数量
int V;		//定义背包的容量
int w[MAXN];	//	储存每件物品的重量w[i]
int c[MAXV];		//储存每件物品的价值c[i]
int better_dp[MAXV];	//一维dp滚动数组(因为只用到第n件物品和第n-1件物品数据,所以可以采取滚动数组优化

void better_knapsack()
{
	//边界处理
	for (int i = 0; i <= V; i++)
		better_dp[i] = 0;
	//状态更新
	for (int i = 1; i <= N; i++)
		//倒序枚举v(V-0)
		for (int v = V; v >= w[i]; v--)	//必须倒序,防止覆盖会用到的值,v>=w[i]就行,否则better_dp[v]=better_dp[v]没意义
			better_dp[v] = max(c[i] + better_dp[v - w[i]], better_dp[v]);		//利用滚动数组
}
int main()
{
	cin >> N >> V;		//输入物品个数和最大的背包容量
	for (int i = 1; i <= N; i++)
		cin >> w[i];
	for (int i = 1; i <= N; i++)
		cin >> c[i];
	better_knapsack();
	
	cout << endl << better_dp[V] << endl;	//输出最大值
	

	return 0;
}
/*
输入数据:
5 8 
3 5 1 2 2 
4 5 2 1 3
*/

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值