从01背包问题理解动态规划

本文通过一个具体的01背包问题实例,介绍了如何利用动态规划的方法解决该问题,并给出了详细的步骤和代码实现。通过构建表格逐步推导出最优解。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

       01背包问题具体例子:

       假设现有容量10kg的背包,另外有3个物品,分别为a1,a2,a3。物品a1重量为3kg,价值为4;物品a2重量为4kg,价值为5;物品a3重量为5kg,价值为6。将哪些物品放入背包可使得背包中的总价值最大?

  动态规划的思路:先将原始问题一般化,欲求背包能够获得的总价值,即欲求前i个物体放入容量为m(kg)背包的最大价值c[i][m]——使用一个数组来存储最大价值,当m取10,i取3时,即原始问题了。而前i个物体放入容量为m(kg)的背包,又可以转化成前(i-1)个物体放入背包的问题。下面使用数学表达式描述它们两者之间的具体关系。

  表达式中各个符号的具体含义。

  w[i] :  第i个物体的重量;

  p[i] : 第i个物体的价值;

  c[i][m] : 前i个物体放入容量为m的背包的最大价值;

  c[i-1][m] : 前i-1个物体放入容量为m的背包的最大价值;

  c[i-1][m-w[i]] : 前i-1个物体放入容量为m-w[i]的背包的最大价值;

  由此可得:c[i][m]=max{c[i-1][m-w[i]]+pi , c[i-1][m]}(下图将给出更具体的解释)



   根据上式,对物体个数及背包重量进行递推,列出一个表格(见下表),表格来自(http://blog.youkuaiyun.com/fg2006/article/details/6766384?reload) ,当逐步推出表中每个值的大小,那个最大价值就求出来了。推导过程中,注意一点,最好逐行而非逐列开始推导,先从编号为1的那一行,推出所有c[1][m]的值,再推编号为2的那行c[2][m]的大小。这样便于理解。

#include<iostream>
//#include<vector>
using namespace std;

int c[10][100]={0};//n+1最大为10,m+1最大为100

void knap(int m,int n){
	int *w=new int[n+1];
	int *p=new int[n+1];
    int i,j;
    for(i=1;i<n+1;i++)
        cin>>w[i]>>p[i];
    for(i=1;i<n+1;i++){
        for(j=1;j<m+1;j++){
			if(j<w[i]){
				c[i][j]=c[i-1][j];
				continue;
			}
			else if(c[i-1][j-w[i]]+p[i]>c[i-1][j])
				c[i][j]=c[i-1][j-w[i]]+p[i];
			else
				c[i][j]=c[i-1][j];
		}
	}
	delete[] w;
	delete[] p;
	w=NULL;
	p=NULL;
}            

int main(){
    int m,n;
	int i,j;
	cin>>m>>n;
    knap(m,n);
	//输出矩阵
    for(i=0;i<=n;i++){
        for(j=0;j<=m;j++)
			cout<<c[i][j]<<"   ";
		cout<<endl;
	}
	system("pause");
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值