算法设计——0-1背包问题(动态规划)

问题

给定n种物品和一背包
wi :物品i的重量
vi :物品i的重量价值
C:背包的容量
问:应如何选择装入背包的物品, 使得装入背包中物品的总价值最大?

分析

p[i][j]代表可选择物品为前i个,背包容量为j时的最大价值
当j<w[i]时说明无法装入第i个物体,此时去掉第i个物品并无影响所以p[i][j]=p[i-1][j]
当j>=w[i]时我们需要判断v[i]+p[i-1][j-w[i]]与p[i-1][j]的大小来对p[i][j]进行赋值

为什么是判断v[i]+p[i-1][j-w[i]]与p[i-1][j]呢
当j>w[i]时,我们可以装入i,价值为v[i],此时容量为j-w[i],且物品到了第i-1个物品,所以p[i][j]可以为v[i]+p[i-1][j-w[i]]
同样,我们也可以不装入此物品,那么此时去掉这个物品并没有影响,就有p[i][j]=p[i-1][j]
由于p[i][j]代表背包容量为j时的最大价值,所以需要比较两种情况的最大值,并填入p[i][j]

用数组s[i][j]记录在容量为j的情况下是否选择第i个物品
在这里插入图片描述

代码实现

#include<stdio.h>
#define N 100
	int w[N],v[N],p[N][N],s[N][N];//p为最大价值,s为选择与否 
void print(int n,int m,int s[][N]){
	if(n<1) return ;
	if(s[n][m]==1){
		print(n-1,m-w[n],s);
		printf("%d ",n);
	}else{
		print(n-1,m,s);
	}
}
int main(){
	int n,m,i,j,k;
	printf("请输入物品种类数目和背包大小:");
	scanf("%d %d",&n,&m);
	printf("请输入各物品所占体积:");
	for(i=1;i<=n;i++){
		scanf("%d",&w[i]);
	}
	printf("请输入各物品的价值:");
	for(i=1;i<=n;i++){
		scanf("%d",&v[i]);
	}
	for(i=0;i<=n;i++){//初始化第零列 
		p[i][0]=0;
		s[i][0]=0;
	}
	for(i=0;i<=m;i++){//初始化第零行 
		p[0][i]=0;
	}
	
	for(i=1;i<=n;i++){//选择前i个物品 
		for(j=1;j<=m;j++){//增大容量 
			if(w[i]>j){//物品不能装入
				p[i][j]=p[i-1][j]; 
				s[i][j]=0;
			}
			else{//可装入时分情况 
				if(v[i]+p[i-1][j-w[i]]>p[i-1][j]){//比较选与不选的价值大小,取大的 
					p[i][j]=v[i]+p[i-1][j-w[i]];
					s[i][j]=1;//选择后为1 
				}else{
					p[i][j]=p[i-1][j];
					s[i][j]=0;//不选为0 
				}
			}	
		}
	}
	printf("最大价值为:%d\n选择的物品为:",p[n][m]);
	print(n,m,s); 
	return 0;
}
 
  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值