背包问题C/C++语言

基于C语言的背包问题(语言只是工具,重要的是思想)

在解决问题之前,为描述方便,首先定义一些变量: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)这一个状态有几种方式?

肯定是两种,第一种是第i件商品没有装进去,第二种是第i件商品装进去了。没有装进去很好理解,就是V(i-1,j);装进去了怎么理解呢?如果装进去第i件商品,那么装入之前是什么状态,肯定是V(i-1,j-w(i))。由于最优性原理(上文讲到),V(i-1,j-w(i))就是前面决策造成的一种状态,后面的决策就要构成最优策略。两种情况进行比较,得出最优。

4、填表,首先初始化边界条件,V(0,j)=V(i,0)=0;

下面给出两个例题:

1、 其中i表示第i个物品,v[i]表示第i个物品的价值,w[i]表示第i个物品的重量(或者说是体积,只是说法不同)***这里的C=13,即容量为13

根据该题,可以画表:(也是题解)

 从表中可知:28即为最大容量为13,能获得的最大价值

2、

这里直接给出表:

 代码如下:!!!!!:光说不练,一点用也没有,只有实际动手了,知识、技能才是自己的。

代码写的比较仓促,可能存在bug,还请谅解。

这份代码主要是提供一个简单的思路吧:

#include<stdio.h>
#include<string.h>

void toBag(int v[],int w[],int len,int size ){
	printf("\n最大容量为:%d\n",size);
	printf("\n商品的体积为:\n");
	for (int i = 0 ; i<len;i++){
		printf("%4d ",w[i]);
	} 
	printf("\n商品的价值为:\n");
	for (int i = 0 ; i<len;i++){
		printf("%4d ",v[i]);
	}
  len=len+1;
  size=size+1;
//  printf("%d  %d",len,size);
  int p[len][size]={1};
  int record[len][size]={0};
  memset(p,0,sizeof(p));
  memset(record,0,sizeof(record));

  for (int i = 1; i<len;i++){
  	for (int j = 1 ; j<size;j++){
  		if (j<w[i-1]){//如果容量不够 .就不选当前这一物品 
  			p[i][j]=p[i-1][j];
  			
		}else{
			int temp = j-w[i-1];
			p[i][j]=p[i-1][j]>(p[i-1][temp]+v[i-1])?p[i-1][j]:(p[i-1][temp]+v[i-1]);
			if (p[i-1][j]<(p[i-1][temp]+v[i-1])){
		     record[i][j]=1;		
			} 
		
		}
//        p[i][j]=1;
  		
	  }
  }
  printf("\n\n记录表:") ; 
   for (int i = 0; i<len;i++){
  	printf("\n");
  	for (int j = 0 ; j<size;j++){
  		printf("%4d ",record[i][j]);
	  }
  }  
  printf("\n");
  printf("\n\n最大价值表:");
  for (int i = 0; i<len;i++){
  	printf("\n");
  	for (int j = 0 ; j<size;j++){
  		printf("%4d ",p[i][j]);
	  }
  }  

  printf("\n"); 
  
  int i = len-1;
  int j=size-1;
  while(i>0){
  	if (record[i][j]==1){
  	 printf("第%d个物品已选\n",i);
	 j-=w[i-1];
	}else{
		printf("第%d个物品未选\n",i);
	}
	i--;
  }
  


}

int main(){
    int w[] ={2,3,4,5};//物品的体积 
    int v[] = {3,4,5,6};//物品的价值 
    int size=8;//背包的最大容量 
    toBag(v,w,sizeof(v)/4,size);



    return 0;
}

下面是一些运行结果:

第一题运行结果:

第二题运行结果:

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值