動態規劃解決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);
	}
	
}


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章