用动态规划的思想解决0-1背包问题(附代码)

 

用动态规划的思想解决0-1背包问题,编程实现:

有n种物品,每种物品仅有一件,第i件物品的重量为wi,价值为vi,现有一个承重量为c的背包。在不超过背包承重的情况下,应如何选择装入背包的物品,使得装入背包中物品的价值总和最大?

样例:n=5,c=8,w={2,2,7,5,4},v={3,6,4,5,6},求背包所装物品的最大价值是多少?最优解是什么?

动态规划的原理:
动态规划与分治法类似,都是把大问题拆分成小问题,通过寻找大问题与小问题的递推关系,解决一个个小问题,最终达到解决原问题的效果。

Vi表示第 i 个物品的价值,Wi表示第 i 个物品的体积,定义V(i,j):当前背包容量 j,前 i 个物品最佳组合对应的价值,同时背包问题抽象化(X1,X2,…,Xn,其中 Xi 取0或1,表示第 i 个物品选或不选)。

1、建立模型,即求max(V1X1+V2X2+…+VnXn);

2、寻找约束条件,W1X1+W2X2+…+WnXn<capacity;

3、寻找递推关系式,面对当前商品有两种可能性:

包的容量比该商品体积小,装不下,此时的价值与前i-1个的价值是一样的,即V(i,j)=V(i-1,j);
还有足够的容量可以装该商品,但装了也不一定达到当前最优价值,所以在装与不装之间选择最优的一个,即V(i,j)=max{V(i-1,j),V(i-1,j-w(i))+v(i)}。
其中V(i-1,j)表示不装,V(i-1,j-w(i))+v(i) 表示装了第i个商品,背包容量减少w(i),但价值增加了v(i);

由此可以得出递推关系式:

j<w(i) V(i,j)=V(i-1,j)
j>=w(i) V(i,j)=max{V(i-1,j),V(i-1,j-w(i))+v(i)}

最优解回溯:
V(i,j)=V(i-1,j)时,说明没有选择第i 个商品,则回到V(i-1,j);
V(i,j)=V(i-1,j-w(i))+v(i)时,说明装了第i个商品,该商品是最优解组成的一部分,随后我们得回到装该商品之前,即回到V(i-1,j-w(i));
一直遍历到i=0结束为止,所有解的组成都会找到。

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

int i,j;
int dp[30][100];
int item[100];

int value[100];
int weight[100];
int GetArray(int a[],int count)
{
	for(int i=1;i<=count;i++)
		cin>>a[i];
}

int GetMaxValue(int n,int m)
{
	for(i=1;i<=n;i++)
	{
		for(j=1;j<=m;j++)
		{
			if(j<weight[i])
				dp[i][j] = dp[i-1][j];
			else
				dp[i][j] = max(dp[i-1][j],dp[i-1][j-weight[i]]+value[i]);
		}
	}
}

int main()
{
	int n,m;
	cin>>n>>m;
	GetArray(value,n);
	GetArray(weight,n);
	GetMaxValue(n,m);
	cout<<"装入背包中物品总价值最大为:"<<endl;
	cout<<dp[n][m]<<endl;
	int b = m;
    for(int i = n; i >= 1; i--){
        if(dp[i][b] > dp[i - 1][b]){
            item[i] = 1;
            b -= weight[i];
        }  
    }
    cout<<"装入的物品的序号为:"<<endl;
    for(int i = 1; i <= n; i++)
        //cout << item[i] << " ";
        if(item[i]==1)
        	cout<<i<<" ";
	cout<<endl;

	return 0;
}

运行结果:

b1a601e172524ff59ab332a9d2580536.png

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值