0/1背包问题---C++动态规划法

【问题】

        给定n种物品和一个背包,物品i(1≤i≤n)的重量是,其价值为,背包容量为,对于每种物品只有两种选择:装入背包或者不装入背包。如何选择装入背包的物品,使得装入背包中物品的总价值最大?

【想法】

首先证明0/1背包问题满足最优性原理。

是0/1背包问题的最优解,则是下面子问题的最优解:

其中要找到

 如若不是子问题最优解,则在子问题必然有一个最优解的前提下,设是上述子问题的一个最优解,则,且。因此,,这说明是0/1背包问题的最优解且比更优,从而导致矛盾。

用0、1表示的装入与否,设表示将n个物品选择性装入容量为C的背包中所获得的最大值。显然,初始子问题是把前面i个物品装入容量为0的背包和把0个物品装入到容量为j的背包中,此时的V值均是0

我们在选择装入时通常遇到两种情况:

一是背包容量足够大,此时自然是装入的物品越多价值越大(尽管没有这样的背包);

二是背包容量有限,我们需要对n件物品进行筛选,选择性价比最高的一种装入方法,而且背包的容量要接近100%使用。

那么会有一下两种状况:

  1. 当我们装到一定程度时,发现背包剩余容量不足以装入第i件物品,那么选择装入第i件物品是的最大价值与选择装入第i-1件物品的最大价值是相同的;
  2. 背包容量可以装第i件物品,那么装入背包价值等于一个拥有容量的背包在i-1件物品中选择是否装入+第i个物品的价值;如果没有装入第i个物品,那么背包中物品的价值等于一个容量为j的背包在i-1件物品中选择装入的价值;显然取二者中价值最大的作为最优解。于是有以下递推式;

 

            

    

接着要确定背包装入了哪些物品,得从后往前推,如果V(n,C)>V(n-1,C),表明第n个物品被装入,将第n个物品踢出,得到一个容量为的背包选择n-1个物品;否则则是一个容量为C的背包选择n-1个物品,以此类推,直到确定第一个物品的装入与否。由此,得到如下函数:

 

             

例如,有5个物品,其重量分别是{2,2,6,5,4},价值分别为{6,3,5,4,6},背包容量为10,用动态规划法求解0/1背包问题,过程如图表所示(动态规划法的核心就是建立图表)

【算法实现】 

#include<iostream>
using namespace std;
#include<cmath>
#include<string>
int V[6][11];
int x[5];
int max(int a,int b)
{
	if(a>b)
		return a;
	else
		return b;	
} 
int KnapSack(int w[],int v[],int n,int C)
{
	int i,j;
	for(i=0;i<=n;i++)//初始化第0列 
		V[i][0]=0;
	for(j=0;j<=C;j++)//初始化第0行 
		V[0][j]=0;
	for(i=1;i<=n;i++)//计算第i行,进行第i次迭代 
	{
		for(j=1;j<=C;j++)
		{
			if(j<w[i-1])
				V[i][j]=V[i-1][j];
			else
				V[i][j]=max(V[i-1][j],V[i-1][j-w[i-1]]+v[i-1]);
		}
	}
	for(i=n,j=C;i>0;i--)//求装入背包的物品 
	{
		if(V[i][j]>V[i-1][j])
		{
			x[i-1]=1;
			j=j-w[i-1];
		}
		else
			x[i-1]=0;
	}
	return V[n][C];//返回背包取得的最大价值 
}
int main()
{
	int w[5]={2,2,6,5,4};
	int v[5]={6,3,5,4,6};
	cout<<"背包最大价值是:"<<KnapSack(w,v,5,10)<<endl;
	cout<<"装入的物品分别是:"; 
	for(int i=0;i<5;i++)
	{
		if(x[i]==1)
			cout<<"物品"<<i+1<<'\t';
	}
	return 0; 
}

【输出结果】

 【结语】

        第一次写文章,所以不是太懂怎么使用编辑器,所以先在Word里先写了初稿,再来编辑这篇文章!对于编辑的方法还有很多没掌握,数学公式编辑器我用的是Math Type,很多东西编辑出来没有预想的结果,希望大家海涵!另外由于本人水平有限,有错误之地还望大家指正批评!

        同时在此祝大家五一劳动节快乐!

  • 30
    点赞
  • 151
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值