动态规划解决0-1背包问题

一、算法说明

1.     问题描述:存在一个背包和N个物品,已知背包的容量C,以及每件物品的重量Wi和价值Pi,每件物品或者完全放入背包或者完全不放入背包,要求选择放入背包的物品,使总重量不能超过背包的容量,同时使物品的总价值最大。

2.     算法分析:和背包问题不同,0-1背包问题无法用贪婪算法解决,故而采用动态规划法解决。

首先将一个0-1背包问题抽象,在上述问题中,用f[i][j]表示对于容量为j(0≤j≤C)的背包在前i(0≤i≤N)个物品中选取价值最大的物品组合时可以获得的最大价值,显而易见有:f[i][0] = f[j][0] = 0, 0≤i≤N, 0≤j≤C

之后,对于任何一个f[i][j],可以拆解为如下子问题:

f[i][j]=f[i-1][j] , if w[i]>j

f[i][j] = max(f[i-1][j],f[i-1][j-w[i]]+p[i]) , if w[i]≤j

其所表达的含义是:对于某一容量,有i个物品的0-1背包问题看做由更小集合上(i-1个物品)的背包问题的延伸。若第i个物品的重量大于当前背包容量(w[i]>j),则该物品不能放入背包,则当前背包问题的解即为前i-1个物品的背包问题;若第i物品的重量小于等于当前背包容量(w[i]≤j),则判断将该物品放入的情况和不将该物品放入的情况,在两者中取最优解(较大者)。

3.     算法实现和性能分析

变量设置:

         n: 物品的个数

         c:背包的容量

         w[n]:物品的重量,w[i]表示第i个物品的重量(0≤i≤n);

         p[n]:物品的价值,p[i]表示第i个物品的价值(0≤i≤n);

         x[n]:最大价值下,物品是否被选择,x[i]=1表示第i件物品被选择,x[i]=0表示第i件物品不被选择(0≤i≤n);

解决0-1背包问题的函数:

         整个函数分为三个阶段,第一,初始化,设置f[i][0]=f[0][j]=0,时间复杂度为n+c,即O(n);第二阶段,逐次计算f[i][j],时间复杂度为n*c,即O(nc); 第三阶段,判断在最大价值下,每个物品是否被放入背包,时间复杂度为n,O(n);

         故整体来看,空间复杂度为n*c+3n,时间复杂度也为n*c+3n。

具体函数如下:

int backge(int n, int w[], int p[], int x[],int c){
		// 初始化
int i = 0; 
		for(i=0;i<c+1;i++){
			f[0][i]=0;
		}
		int j=0;
		for(j=0;j<n+1;j++){
			f[j][0] =0;
			x[j]=0;
		}
		//逐次计算f[i][j]
		for(i=1;i<n+1;i++){
			for(j=1;j<c+1;j++){
				if(w[i-1]>j){
					f[i][j]=f[i-1][j];
				}else{
					f[i][j]=max(f[i-1][j],f[i-1][j-w[i-1]]+p[i-1]);//max()函数事先定义
				}
			}
		}
		//判断在最大价值下,每个物品是否被放入背包
		j=c;
		for(i=n;i>0;i--){
			if(f[i][j]>f[i-1][j]){
				x[i-1]=1;
				j =j -w[i-1];
			}
		}
	return f[n][c];//返回最大价值
}

二:实验,结果统计及分析

         实验数据设置:

                  c:固定800

                  n:随机生成15-40

                  w[i]:随机生成0-1000

                  p[i]:随机生成0-100

         进行50次实验:

         实验结果截图如下:



从实验数据来看,每次的运行时间都在一个毫秒左右,使用clock()无法统计更精确的运行时间,所以无法进行较为精确的分析。

全部代码如下:

#include <stdio.h>
#include <stdlib.h>
#include <time.h>
//the num of the goods less than 101 and the capaticy of the backage less that 1000; 
int f[50][1000];
int x[50];
//the function which return the bigger one of a and b
int max(int a, int b){
	if(a>b){
		return a;
	}else{
		return b;
	}
}
// the function for 0-1 backage problem 
int backage(int n, int w[], int p[], int x[], int c){
	int i = 0;
	for(i=0;i<c+1;i++){
		f[0][i]=0;
	}
	int j=0;
	for(j=0;j<n+1;j++){
		f[j][0] =0;
		x[j]=0;
	}
	for(i=1;i<n+1;i++){
		for(j=1;j<c+1;j++){
			if(w[i-1]>j){
				f[i][j]=f[i-1][j];
			}else{
				f[i][j]=max(f[i-1][j],f[i-1][j-w[i-1]]+p[i-1]);
			}
		}
	}
	j=c;
	for(i=n;i>0;i--){
		if(f[i][j]>f[i-1][j]){
			x[i-1]=1;
			j =j -w[i-1];
		}
	}
	return f[n][c];
}
int main(){
	int c = 800;
	int result;
	for(int count =0 ;count<50;count++){
		srand(count);
		int num = rand()%26+15;
		//int num=45;
		int p[num];
		int w[num];
		for( int i =0; i<num;i++){
			w[i] = rand()%1000;
			p[i] = rand()%100;
		}
		clock_t begin = clock();
		result = backage(num,w,p,x,c);
		clock_t finish = clock();
		long interval = finish - begin;
		printf("nums:%i   ",num);
		printf("begintime:%ld   ",begin);
		printf("finishtime:%ld   ",finish);
		printf("result:%i   ", result);
		printf("used time:%ld\n",interval);
	}
	
}


  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值