一、算法說明
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);
}
}