c++ 动态规划-01背包

                                       动态规划 - 01背包问题

1.使用递归遍历(穷举)求解:

      01背包问题:给定 n 种物品和一个重量(容量)(限定条件)为 w 的背包,物品 i 的重量是 wi,其价值为 vi。(每种物品只有一个)问:如何选择装入背包的物品,使得装入背包中的物品的价值最大。

//VC6.0--------------------------
#include"stdafx.h"
#include <cmath>
#include <iostream>
using namespace std;

//----------全局变量------------
#define n 4	//number     //物品数量
#define max_w 9	//weight //可承受重量(最大重量)
int value[n]={2,3,4,5};  //物品价值
int weight[n]={3,4,5,6}; //物品重量
//最大价值   以及解向量
int max_v=0;  int x[n]={0};
int nx[n]={0}; //当前解的情况
//-----------------------递归-----------------------
void beibao01(int i,int v,int w) //第i个物品  总价值  总重量
{
	//物品已遍历完毕
	if(i>n-1) return;   
	//将第i个物品放入 改变解向量 
	if((w+weight[i]) <= max_w)
	{
		nx[i]=1;
		//如果大于之前的解的最大价值  则更新最大价值以及解向量
		if((v+value[i]) > max_v)
		{
			max_v = v+value[i];
			for(int k=0;k<n;k++) x[k]=nx[k];
		}
		beibao01(i+1,v+value[i],w+weight[i]);
	}
	//不放第i个物品  刷新解向量 
	for(int k=i;k<n;k++) nx[k]=0;
	beibao01(i+1,v,w);
}

//------------------------------------------------------
void main()
{
	beibao01(0,0,0);
	//输出答案
	cout<<max_v<<endl;
	for(int k=0;k<n;k++) cout<<x[k]<<" ";
}

max_w=8: 

 

2. 动态规划算法求解

//VC6.0--------------------------
#include "stdafx.h"
#include <cmath>
#include <iostream>
using namespace std;

int max(int a,int b){
	if(a>b) return a;
	else return b;
}
void solution(int i,int j);

//----------全局变量------------
#define n 4	    //number //物品数量
#define max_w 9	//weight     //可承受重量(最大重量)
int value[n]={2,3,4,5};      //物品价值
int weight[n]={3,4,5,6};     //物品重量

int max_v=0;  int x[n]={0};  //最大价值   以及解向量
int real_w=0;                //包含最大价值背包的实际重量
//动态规划表 dynamic programming table
int dpt[n][max_w+1]={0};     // dpt[i][j]=k 表示前i个物品装在承重为j的背包中的最大价值为k

//-----------------------状态转移方程-----------------------
//不考虑单个物品重量超过max_w  不考虑单个物品价值为0  等特殊情况
void beibao01() //解出动态规划表以及 最大价值 背包实际重量 解向量
{
	int i,j;
	//先填写第一行表
	for (j = 0; j <= max_w; j++)
		if(j >= weight[0])
			dpt[0][j] = value[0];
		else
			continue;
	//由递推式 填完表
	for (i = 1; i < n; i++) {
		for (j = 1; j <= max_w; j++) {
			//容量为j的背包装不下 第i个物品
			if (j < weight[i])
				dpt[i][j] = dpt[i-1][j];
			//能装下 装完第i个物品之后背包重量为j   则其价值为 dpt[i-1][现在重量-第i物品重量] + 第i物品价值
			else{
				//取其最大值 即为最优子策略
				dpt[i][j] = max(dpt[i-1][j], dpt[i-1][j-weight[i]] + value[i]);
				if(dpt[i][j] > max_v){
					max_v = dpt[i][j];
					real_w = j;
				}
			}
		}
	}
	//求一个最优解
	solution(n-1,real_w);
}
//----------求解向量-------------
void solution(int i,int j)
{
	//第一个物品是否放入背包?
	if(i == 0){
		//没有放入
		if(j == 0) x[i] = 0;
		else x[i] = 1;
	}
	else{
		//第i个物品没有放入包内 寻找上一个最优子策略
		if(dpt[i][j] == dpt[i-1][j]){
			x[i] = 0;
			solution(i-1,j);
		}
		//第i个物品放入了包内  寻找上一个最优子策略
		else{
			x[i] = 1;
			solution(i-1,j-weight[i]);
		}
	}
}
//------------------------------------------------------
void main()
{
	int i,j;
	beibao01();

	//输出答案
	cout<<"物品价值:"<<endl;
	for (i = 0; i < n; i++) 
		cout<<value[i]<<" ";
	cout<<endl;
	cout<<"物品重量:"<<endl;
	for (i = 0; i < n; i++) 
		cout<<weight[i]<<" ";
	cout<<endl;
	cout<<"动态规划表:"<<endl;
	for (i = 0; i < n; i++) {
		for (j = 0; j <= max_w; j++) {
			cout << dpt[i][j] << ' ';
		}
		cout << endl;
	}
	cout<<"实际重量:"<<real_w<<endl;
	cout<<"最大价值:"<<max_v<<endl;
	cout<<"解向量:";
	for(int k=0;k<n;k++) cout<<x[k]<<" ";
	cout<<endl;
}

max_w=8:

max_w=9:

3.对2进行简化

//VC6.0--------------------------
#include "stdafx.h"
#include <cmath>
#include <iostream>
using namespace std;
//----------全局变量(输入信息)------------
#define n 4		     //数量
#define max_w 8	             //最大重量
int value[n]={2,3,4,5};      //价值
int weight[n]={3,4,5,6};     //重量

//----------最大值函数--------
int max(int a,int b){
	if(a>b) return a;
	else return b;
}
//-----------------------填写动态规划表-----------------------
int beibao01(int *x) 
{
	int i,j;
	int dpt[n][max_w+1]={0};  //动态规划表
	int max_v;                //最大价值
	int real_w;               //实际重量

	//--------------第一行------------
	for (j = 0; j <= max_w; j++)
		if(j >= weight[0])
			dpt[0][j] = value[0];
	//--------------其余行------------
	for (i = 1; i < n; i++) 
	{
		for (j = 1; j <= max_w; j++)
		{
			if (j < weight[i])
				dpt[i][j] = dpt[i-1][j];
			else
			{
				dpt[i][j] = max(dpt[i-1][j], dpt[i-1][j-weight[i]] + value[i]);
			}
		}
	}
	//求最大价值 以及实际重量
	for (j = 1; j <= max_w; j++)
	{
		if(dpt[n-1][j] > max_v)
		{
			max_v = dpt[n-1][j];
			real_w = j;
		}
	}
	//求一个最优解
	for (i = n-1; i > 0; i--) 
	{
		if(dpt[i][real_w ] != dpt[i-1][real_w ])
		{
			x[i] = 1;
			real_w = real_w-weight[i];
		}
	}
	if(real_w != 0) 
		x[0] = 1;
	//返回最大值
	return max_v;
}

//------------------------------------------------------
void main()
{
	//解向量
	int x[n]={0};
	//输出答案
	cout<<"最大价值:"<<beibao01(x)<<endl;
	cout<<"解向量:";
	for(int k=0;k<n;k++) 
		cout<<x[k]<<" ";
	cout<<endl;
}

max_w=8: 

 

 参考博文:https://blog.csdn.net/qq_38410730/article/details/81667885

  • 1
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

大米粥哥哥

感谢认可!

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值