<span style="font-family: Arial, Helvetica, sans-serif; background-color: rgb(255, 255, 255);">给定n种物品和一背包。物品i的重量是wi,其价值为vi,背包的容量为C。问应如何选择装入背包的物品,使得装入背包中物品的总价值最大?</span>
<span style="font-family: Arial, Helvetica, sans-serif; background-color: rgb(255, 255, 255);">
</span>
0-1背包问题是一个特殊的整数规划问题。
设所给0-1背包问题的子问题
的最优值为m(i,j),即m(i,j)是背包容量为j,可选择物品为i,i+1,…,n时0-1背包问题的最优值。由0-1背包问题的最优子结构性质,可以建立计算m(i,j)的递归式如下。
算法复杂度分析:
从m(i,j)的递归式容易看出,算法需要O(nc)计算时间。当背包容量c很大时,算法需要的计算时间较多。例如,当c>2n时,算法需要Ω(n2n)计算时间。
下面是自己写的一段代码:
// 01背包算法经典法.cpp : 定义控制台应用程序的入口点。
//
#include "stdafx.h"
#include <iostream>
using namespace std;
int max(int a,int b){
if(a>=b){
return a;
}
else{
return b;
}
}
int min(int a,int b){
if(a<b){
return a;
}
else{
return b;
}
}
void Knapsack(int *v,int *w,int c,int n,int m[][100]){//计算背包中所有物品的最大价值
int JMax=min(w[n]-1,c);
for(int j=0;j<=JMax;j++)m[n][j]=0;
for(int j=w[n];j<=c;j++)m[n][j]=v[n];
for(int i=n-1;i>=1;i--){//最后一个物品放不放入的运算,放在循环里或者循环外都是可以的,区别是循环外就少算了m[1][0]到m[1][c-1],因为这些在计算中用不到了。
JMax=min(w[i]-1,c);
for(int j=0;j<=JMax;j++)m[i][j]=m[i+1][j];
for(int j=w[i];j<=c;j++)m[i][j]=max(m[i+1][j],m[i+1][j-w[i]]+v[i]);
}
//m[1][c]=m[2][c];
//if(c>=w[1])m[1][c]=max(m[1][c],m[2][c-w[1]]+v[1]);
cout<<m[1][c]<<endl;
}
void Traceback(int m[][100],int *w,int c,int n,int *x){
for(int i=1;i<n;i++){
if(m[i][c]==m[i+1][c])x[i]=0;
else{x[i]=1;c-=w[i];}
x[n]=(m[n][c])?1:0;
}
for(int i=1;i<=n;i++){
if(x[i]==1){
cout<<i<<" ";
}
}
}
int _tmain(int argc, _TCHAR* argv[])
{
int c;//c代表背包的容量
int v[100];//每一个v代表第i个物品的价值
int w[100];//每一个w代表第i个物品的重量
int n;//n代表总的物品个数
int m[100][100];//m[][]存放动态规划的计算结果
int x[100];//x[]存放第i个物品是否被放入背包
cout<<"输入背包的容量:";
cin>>c;
cout<<"输入物品总数:";
cin>>n;
for(int i=1;i<=n;i++){
cout<<"输入第"<<i<<"个物品的重量和价值:";
cin>>w[i]>>v[i];
}
Knapsack(v,w,c,n,m);
Traceback(m,w,c,n,x);
return 0;
}