给定n种物品和一背包。物品i的重量是wi,其价值为vi,背包的容量为C。
问应如何选择装入背包的物品,使得装入背包中物品的总价值最大
对于一种物品,要么装入背包,要么不装。所以对于一种物品的装入状态可以取0和1.
我们设物品i的装入状态为xi,xi∈ (0,1),此问题称为0-11背包问题。
过程分析
数据:物品个数n=5,物品重量w[n]={2,2,6,5,4},物品价值V[n]={6,3,5,4,6},
总重量c=10.背包的最大容量为10,那么在设置数组m大小时,可以设行列值为6和11,
那么,对于m(i,j)就表示可选物品为i…n背包容量为j(总重量)时背包中所放物品的最大价值。
动态规划
#include<stdio.h>
#define n 5
#define c 10
//int j;
int w[n]={2,2,6,5,4};
int v[n]={6,3,5,4,6};
int s[n][c+1];
int knap(){
for(int j=0;j<=c;j++){//j表背包容量
if(j<w[n-1])
s[n-1][j]=0;
else s[n-1][j]=v[n-1];//当j>=w[n-1]时,表背包可以放入物体n-1,故其价值为v[n]
}
for(int i=n-2;i>=0;i--){
for(int j=0;j<=c;j++){
if(j<w[i])
s[i][j]=s[i+1][j];
else s[i][j]=s[i+1][j]>(s[i+1][j-w[i]]+v[i])?s[i+1][j]:(s[i+1][j-w[i]]+v[i]);
}
}
int t=c;
for(int i=0;i<n-1;i++)
if(s[i][t]!=s[i+1][t]){
printf("%5d",i);
t=t-w[i];//如果放进去了,背包的容量就会相应减少
}
if(t>=w[n-1])
printf("%5d",n-1);
}
int main(){
printf("0-1背包最优解为:");
knap();
printf("\n");
printf("s数组元素为:\n");
for(int i=0;i<n;i++){
for(int j=0;j<=c;j++){
printf("%5d",s[i][j]);
}
printf("\n");
}
printf("0-1最优值为:%d\n",s[0][c]);
return 0;
}
回溯法
#include<stdio.h>
#include<math.h>
#define n 5
#define c 10
int w[n]={2,2,6,5,4};
int v[n]={6,3,5,4,6};
int s[n][c+1];
int max=0;
int countv=0;
int countw=0;
int x[n];
int bestx[n];
void trace(int t){
if(t==n){
if(countw<=c){
if(countv>max){
max=countv;
for(int i=0;i<n;i++)
bestx[i]=x[i];
}
}
return;
}
countv+=v[t];
countw+=w[t];
x[t]=1;
if(countw<=c)
trace(t+1);
countw-=w[t];
countv-=v[t];
x[t]=0;
trace(t+1);
}
int main(){
trace(0);
printf("%d",max);
for(int i=0;i<n;i++)
if(bestx[i]==1)
printf("%5d",i);
return 0;
}