01背包问题

原创 2016年08月29日 19:45:37

01背包问题是经典的动态规划问题,问题描述如下:


我们用f[i][j]表示将前i个物品放入容量为j的背包里所能获得的最大价值,则状态转移方程如下:


具体程序如下:

#include "stdafx.h"
#include<iostream>
#include<vector>
using namespace std;
int maxValue(vector<int>weight,vector<int>value,int bagCapacity)
{
	int m=weight.size();
	int n=bagCapacity;
	vector<vector<int>>dp(m+1,vector<int>(n+1,0));
	vector<int> rollDp(n+1,0);
	for(int i=0;i<m;++i)
	{
		for(int j=n-1;j>=0;--j)
		{
			if(weight[i]<=j+1)
			{
				dp[i+1][j+1]=max(dp[i][j+1],dp[i][j+1-weight[i]]+value[i]);  //当内循环从右到左时,可以用滚动数组来优化空间复杂度。
				rollDp[j+1]=max(rollDp[j+1],rollDp[j+1-weight[i]]+value[i]); //用于滚动数组降低空间复杂度
			}
			else
			{
				dp[i+1][j+1]=dp[i][j+1];
			}

		}
	}
	cout<<"滚动数组所得结果为: "<<rollDp[n]<<endl;  //滚动一维数组输出结果和二维数组一致
	return dp[m][n];
}
int main()
{ 
	int numCnt=0;   //物品数目
	int bagCapacity=0;  //背包容量
	while(cin>>numCnt>>bagCapacity)
	{
		vector<int>weight(numCnt,0);
		vector<int>value(numCnt,0);
		for(int i=0;i<numCnt;++i)
		{
			cin>>value[i];
		}
		for(int i=0;i<numCnt;++i)
		{
			cin>>weight[i];	
		}
		cout<<"最大价值为: "<<maxValue(weight,value,bagCapacity);
	}
}
程序运行结果如下:


上述输入第一行第一个数代表物品个数,第二个数代表背包最大容量;第二行每个数分别代表对应的物品的价值,第三行每个数分别代表对应物品的重量。

从程序中我们可以看到如果利用二维数组dp来编写程序,就是完全按照我们之前写的状态转移方程来写,这个很好理解,但是空间复杂度为O(N*W)。我们注意到状态转移方程中dp[i][j]只与dp[i-1][]有关(第二维空着不是笔误哦,我是想表达的是外层的第i个循环的值,只与外层的第i-1个循环的值决定,这样一来,内层循环不管顺序还是逆序都可以,自己思考一下为什么?),而当内层循环逆序的时候,我们通常可以用一维数组来代替二维数组,原因如下:这种情况下我们可以用dp[j]取代dp[i][j]是因为计算dp[i][j]前,我们已经计算了dp[i-1][j],所以如果我们之前是用的一维数组dp[j]的话,那计算dp[i][j]前一瞬间,dp[j]代表的是dp[i-1][j],dp[i][j]计算完后,dp[j]表示的就是dp[i][j],程序中我将这两种方法写到了一起,方便领悟其中的差别。现在我们思考一个问题,为什么用一维数组的时候,内层循环必须是逆序,不能顺序?原因是

dp[i+1][j+1]=max(dp[i][j+1],dp[i][j+1-weight[i]]+value[i]),注意到式中有dp[i][j+1-weight[i]],如果假设j+1-weight[i]=3,那当我们求dp[i+1][j+1],而j=6时,此时用二维数组肯定不会有问题,但是用一维数组且内循环顺序增长时,此时dp[j+1]即dp[7]可能与dp[3]有关,但此时的dp[3]已经是dp[i+1][3]了,而不再是dp[i][3],违背了我们的状态转移方程。



版权声明:本文为博主原创文章,未经博主允许不得转载。

相关文章推荐

01背包问题

  • 2012年11月27日 13:04
  • 169KB
  • 下载

01背包问题

  • 2013年03月25日 21:34
  • 4KB
  • 下载

动态规划的01背包问题---关于国王开矿的故事

此为引用的一篇文章,很棒,地址如下: http://blog.renren.com/share/228709498/2675290555 ----第一节----初识动态规划-------- ...

01背包问题C

  • 2014年05月24日 20:07
  • 2.17MB
  • 下载

01背包问题

  • 2012年12月16日 15:00
  • 1KB
  • 下载

动态规划_01背包问题_Java实现

什么是动态规划?动态规划就是将一个大问题不断向下拆分成小问题,直到拆分出的小问题可以求出其解,然后将小问题的解不断的向上合并,最终得到大问题的解决方案。...

01背包问题

  • 2015年03月25日 13:53
  • 2KB
  • 下载

C++编写的01背包问题

  • 2015年07月07日 10:52
  • 1.25MB
  • 下载

动态规划 01背包问题

这篇文章,去年2月份看到了,但是当时根本不太懂,所以没用动态规划,直接暴力枚举解决的问题 ,原因主要是对递归了解不深,现在隔了快1年,再次翻到,终于弄懂了,主要是对递归的理解深入了很多 .      ...

01背包问题 回溯法

  • 2009年05月17日 16:56
  • 6KB
  • 下载
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:01背包问题
举报原因:
原因补充:

(最多只允许输入30个字)