从01背包进化到完全背包
已熟练01背包,是时候进化到完全背包了。
1.原始的仿01背包写完全背包
以下代码是仿01背包编写的代码,却无法AC。
#include <stdio.h>
int f[35][210],w[210],c[210];
int M,N;
int max(int a,int b){
return a>b?a:b;
}
int main(){
int i,j,k;
scanf("%d%d",&M,&N);
for(i=1;i<=N;i++)scanf("%d%d",&w[i],&c[i]);
for(i=1;i<=N;i++)
for(k=1;k*w[i]<=M;k++)
for(j=0;j<=M;j++)
if(j>=k*w[i])f[i][j]=max(f[i][j],f[i][j-k*w[i]]+k*c[i]),f[i][j]=max(f[i][j],f[i-1][j-k*w[i]]+k*c[i]),f[i][j]=max(f[i][j],f[i-1][j]);
else f[i][j]=max(f[i][j],f[i-1][j]);
printf("max=%d\n",f[N][M]);
return 0;
}
提供上述代码无法AC的数据
Input:
35 8
12 9
2 3
4 9
6 7
14 2
80 5
20 20
10 8
Output:
max=75
请特别关注第6个物体80 5,重量超越了背包承受的重量,造成了f[6][]一系列数据出错。
以下为改进后AC的代码。
#include <stdio.h>
int f[35][210],w[210],c[210];
int M,N;
int max(int a,int b){
return a>b?a:b;
}
int main(){
int i,j,k;
scanf("%d%d",&M,&N);
for(i=1;i<=N;i++)scanf("%d%d",&w[i],&c[i]);
for(i=1;i<=N;i++)
for(k=0;k*w[i]<=M;k++)
for(j=0;j<=M;j++)
if(j>=k*w[i])f[i][j]=max(f[i][j],f[i][j-k*w[i]]+k*c[i]),f[i][j]=max(f[i][j],f[i-1][j-k*w[i]]+k*c[i]),f[i][j]=max(f[i][j],f[i-1][j]);
printf("max=%d\n",f[N][M]);
return 0;
}
请特别关注第6个物体80 5,重量超越了背包承受的重量,上述代码,照样能对f[6][]数据进行完好处理。
问题归结为,装不进物体,造成的错误。
优化上述代码
#include <stdio.h>
int f[35][210],w[210],c[210];
int M,N;
int max(int a,int b){
return a>b?a:b;
}
int main(){
int i,j,k;
scanf("%d%d",&M,&N);
for(i=1;i<=N;i++)scanf("%d%d",&w[i],&c[i]);
for(i=1;i<=N;i++)
for(k=0;k*w[i]<=M;k++)
for(j=0;j<=M;j++)
if(j>=k*w[i])f[i][j]=max(f[i][j],f[i][j-k*w[i]]+k*c[i]),f[i][j]=max(f[i][j],f[i-1][j-k*w[i]]+k*c[i]);
printf("max=%d\n",f[N][M]);
return 0;
}
继续研究数据生成过程,进一步优化上述代码
#include <stdio.h>
int f[35][210],w[210],c[210];
int M,N;
int max(int a,int b){
return a>b?a:b;
}
int main(){
int i,j,k;
scanf("%d%d",&M,&N);
for(i=1;i<=N;i++)scanf("%d%d",&w[i],&c[i]);
for(i=1;i<=N;i++)
for(k=0;k*w[i]<=M;k++)
for(j=0;j<=M;j++)
if(j>=k*w[i])f[i][j]=max(f[i][j],f[i-1][j-k*w[i]]+k*c[i]);
printf("max=%d\n",f[N][M]);
return 0;
}
再接再励,继续阅读代码,发现还有可改进的地方。2019-12-24 21:25
#include <stdio.h>
int f[35][210],w[210],c[210];
int M,N;
int max(int a,int b){
return a>b?a:b;
}
int main(){
int i,j,k;
scanf("%d%d",&M,&N);
for(i=1;i<=N;i++)scanf("%d%d",&w[i],&c[i]);
for(i=1;i<=N;i++)
for(k=0;k*w[i]<=M;k++)
for(j=k*w[i];j<=M;j++)
f[i][j]=max(f[i][j],f[i-1][j-k*w[i]]+k*c[i]);
printf("max=%d\n",f[N][M]);
return 0;
}
能否省去k这重循环呢,仔细分析了数据生成过程,一种物品被选中多次,对结果也是有影响的,故上述代码,已是最优化,不能省去k这重循环,是否真的如此呢,那就看看标准的完全背包写法。2019-12-24 21:30
对比了之前的代码https://blog.csdn.net/mrcrack/article/details/78440134发现上述代码编写确实有独到之处,全网唯一。2019-12-24 21:44
算法精髓,数据模拟。洞悉数据流向。2019-12-24 21:46
瞟了一眼从前编写的代码,发现有回避k这重循环的算法,那么只好在上面代码的基础上静下心来想。
以下为回避k这重循环的算法
#include <stdio.h>
int f[35][210],w[210],c[210];
int M,N;
int max(int a,int b){
return a>b?a:b;
}
int main(){
int i,j,k;
scanf("%d%d",&M,&N);
for(i=1;i<=N;i++)scanf("%d%d",&w[i],&c[i]);
for(i=1;i<=N;i++)
for(j=0;j<=M;j++){
f[i][j]=max(f[i][j],f[i-1][j]);//或者一个同种物体都不放
if(j>=w[i])f[i][j]=max(f[i][j],f[i][j-w[i]]+c[i]);//贪心,尽可能的多放同种物品
}
printf("max=%d\n",f[N][M]);
return 0;
}
2.原始的仿01背包写完全背包,进行滚动数组优化
//滚动数组优化,
//样例通过,提交AC。2019-12-24 21:26
#include <stdio.h>
int f[2][210],w[210],c[210];
int M,N;
int max(int a,int b){
return a>b?a:b;
}
int main(){
int i,j,k;
scanf("%d%d",&M,&N);
for(i=1;i<=N;i++)scanf("%d%d",&w[i],&c[i]);
for(i=1;i<=N;i++)
for(k=0;k*w[i]<=M;k++)
for(j=k*w[i];j<=M;j++)
f[i%2][j]=max(f[i%2][j],f[(i-1)%2][j-k*w[i]]+k*c[i]);
printf("max=%d\n",f[N%2][M]);
return 0;
}
//滚动数组优化,回避k这重循环的算法.2019-12-25
#include <stdio.h>
int f[2][210],w[210],c[210];
int M,N;
int max(int a,int b){
return a>b?a:b;
}
int main(){
int i,j,k;
scanf("%d%d",&M,&N);
for(i=1;i<=N;i++)scanf("%d%d",&w[i],&c[i]);
for(i=1;i<=N;i++)
for(j=0;j<=M;j++){
f[i%2][j]=max(f[i%2][j],f[(i-1)%2][j]);//或者一个同种物体都不放
if(j>=w[i])f[i%2][j]=max(f[i%2][j],f[i%2][j-w[i]]+c[i]);//贪心,尽可能的多放同种物品
}
printf("max=%d\n",f[N%2][M]);
return 0;
}
3.一维数组 2019-12-25
#include <stdio.h>
int f[210],w[210],c[210];
int M,N;
int max(int a,int b){
return a>b?a:b;
}
int main(){
int i,j,k;
scanf("%d%d",&M,&N);
for(i=1;i<=N;i++)scanf("%d%d",&w[i],&c[i]);
for(i=1;i<=N;i++)
for(j=w[i];j<=M;j++)
f[j]=max(f[j],f[j-w[i]]+c[i]);
printf("max=%d\n",f[M]);
return 0;
}