背包问题

背包问题

          背包问题是DP,也是贪心问题。下面进行举例,我们假设背包的容量为8,有4件物品,编号分别为1,2,3,4,体积分别为2,3,4,5,价值分别为3,4,5,6 。问装入价值最大为多少(初级)以及是那几件物品(进阶),当然每件物品放一次。

          先来分析解决第一个问题,装入价值最大为多少,使用DP。先列个表,然后分析得出状态转移方程。如下表所示,为什么只有四件物品却要有五个编号。当什么都没放的时候,我们记为编号0。当然不管背包容量多少,不放东西时价值都为0.

          从编号1的物品开始分析,没有容量或者容量不够时,价值为0,当容量大于等于2时,只考虑物品1的时候,价值均为3;接下来分析物品2,容量0~2显然存不下物品2的,价值等于上一行的值,容量3,考虑物品2放还是不放,进行比较,显然放的时候价值最大;容量4的时候物品1放不下,做法和3一样;容量为5的时候,显然放下1,2物品时价值最大,下面以此类推

          根据上述表格的分析,我们可以得出状态转移方程。假设物品体积我们用数组c[]表示,价值用数组val[]表示。

          1.状态转移方程:f[i][j] = f[i-1][j] (当前物品装不下时)

                                       f[i][j] = max(f[i-1][j], val[i] + f[i][j-c[i]]) (当前物品可以装时,第二个表达式为当前容量去除当前物品的容量的最大值)

          2.选用二维数组作为数据结构

          3.初始化,将第一行初始化为0

         第二个问题分析:我们在第一个问题的基础上进行分析,已经找到了最大的价值,那么比对一下上一次加的是哪个情况下的值(上述两种情况),去确定是几号物品,使用回溯法。

         结束条件:i=0,遍历到没有物品时结束

         all station:考虑两种情况的比对,然后递归下一次

推荐B站视频学习:https://www.bilibili.com/video/BV1K4411X766?from=search&seid=3866792667009135377

 

参考代码:(第一个问题)

class Solution{
public:
	vector<int> object;
	int b_b(vector<int>& c, vector<int>& val, int capacity)
	{
		//DP
		vector<vector<int>> f(c.size(), vector<int>(capacity + 1,0));
		//填表
		for (int i = 1; i < c.size(); i++)
		{
			for (int j = 1; j <= capacity; j++)
			{
				if (c[i] <= j)
				{
					f[i][j] = max(f[i-1][j],f[i-1][j-c[i]]+val[i]);
				}
				else{
					f[i][j] = f[i-1][j];
				}
			}
		}
		find_object(f,val,c,4,8);
		return f[c.size()-1][capacity];
	}

	void find_object(vector<vector<int>>& dp, vector<int>& val, vector<int>& c, int i, int j)
	{
		if (i == 0)
		{
			return;//找完了
		}

		if (dp[i][j] == dp[i - 1][j])
		{
			object[i] = 0;
			find_object(dp, val, c, i - 1, j);
		}
		else if (dp[i][j] == dp[i - 1][j - c[i]] + val[i])
		{
			object[i] = 1;
			find_object(dp, val, c, i - 1, j-c[i]);
		}
	}
};
int main()
{
	Solution solution;
	solution.object.resize(5);
	vector<int> c;
	vector<int> val;
	for (int i = 0; i <= 4; i++)
	{
		if (i == 0)
		{
			c.push_back(i);
			val.push_back(i);
		}
		else{
			c.push_back(i+1);
			val.push_back(i+2);
		}
	}
	cout << solution.b_b(c,val,8) << endl;
	system("pause");
	return 0;
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值