问题:给定一个容积为c的背包,去尝试装n个重量为wi、价值为vi的物体,求能装下的物体的最大价值。
解法一:暴力
分析:0-1背包只有两种选择,放与不放到背包里,采用二进制表示,1表示放入背包,0表示不放入背包,因此我们基于二进制进行暴力搜索。
#include<stdio.h>
#include<math.h>
#define n 5
int weight[n]={12,2,1,4,1};
int value[n]={4,2,1,10,2};
int c=15;
int main(){
int maxvalue=0;
int tempvalue,tempweight,temp,maxnum;
for(int num=0;num<pow(2,n);num++){
temp=num;
tempvalue=0;
tempweight=0;
for(int i=0;i<n;i++){
if(temp%2){
tempvalue+=value[i];
tempweight+=weight[i];
}
temp/=2;
}
if(tempweight<=c&&tempvalue>maxvalue){
maxvalue=tempvalue;
maxnum=num;
}
}
for(int i=0;i<n;i++){
if(maxnum%2)
printf("%2d",weight[i]);
maxnum/=2;
}
printf("\n该重量最大价值%d\n",maxvalue);
return 0;
}
解法二:递归
分析:若飞f(i,j)表示考虑第i个物品时背包剩余容积为j
j>=w[i]f(n,j)=v[i];
(1)i==n时:
当j<w[i] ,f(n,j)=0;当j>=w[i], f(i,j)=v[i];
(2)i<n时:
当j<w[i], f(i,j)=f(i+1,j);当j>=w[i], f(i,j)=max(f(i+1,j),f(i+1,j-w[i])+v[i]);
#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 f(int i,int j){//第i个物体,剩余容积
int m1,m2;
if(i==n-1){
if(j>=w[i])
return v[i];
return 0;
}
if(j<w[i]){
return f(i+1,j);
}
m1=f(i+1,j);
m2=f(i+1,j-w[i])+v[i];
return m1>m2?m1:m2;
}
int main(){
printf("%d\n",f(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 main(){
int s[n][c+1];
int i,j;
for(j=0;j<c+1;j++){
if(j>=w[n-1]){
s[n-1][j]=v[n-1];
}
else{
s[n-1][j]=0;
}
}
for(i=n-2;i>=0;i--){
for(j=0;j<c+1;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]);
}
}
printf("%4d\n",s[0][c]);
j=c;
for(i=0;i<n-1;i++){
if(s[i][j]!=s[i+1][j]){
printf("%4d",i+1);
j-=w[i];
}
}
if(j>=w[n-1]){
printf("%4d",n);
j-=w[i];
}
return 0;
}
解法四:备忘录
int s[n][c+1];
int f(int i,int j){
int m1,m2;
if(s[i][j]==0)
return s[i][j];
if(i==n-1){
if(j>=w[i])
s[i][j]=v[i];
else
s[i][j]=0;
}
else{
if(j<w[i])
s[i][j]=f(i+1,j);
else{
m1=f(i+1,j);
m2=f(i+1,j-w[i])+v[i];
s[i][j]=m1>m2?m1:m2;
}
}
return s[i][j];
}
int main(){
int i,j;
for(i=0;i<n;i++){
for(j=0;j<c+1;j++){
s[i][j]=-1;
}
}
printf("%4d\n",f(0,c));
j=c;
for(i=0;i<n-1;i++){
if(s[i][j]!=s[i+1][j]){
printf("%4d",i+1);
j-=w[i];
}
}
if(j>=w[n-1]){
printf("%4d",n);
j-=w[i];
}
return 0;
}