完全背包及降维
问题模型
给定n个物品,其中第i个物品的体积为\(V_i\),价值为\(W_i\),并且有无数个,有一容积为M的背包将物品放入背包,使得最后的体积最大。
方法一:
for(int i=1;i<=n;i++){
for(int j=0;j<=m;j++){
for(int k=0;k<=j/v[i];k++){
f[i][j]=max(f[i][j],f[i-1][j-k*v[i]]+w[i]*k);//动态转移方程
}
}
}
#include<iostream>
#include<cstdio>
#define MAXN 110
using namespace std;
inline int read(){
int s=0,w=1;
char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')w=-1;ch=getchar();}
while(ch>='0'&&ch<='9') s=s*10+ch-'0',ch=getchar();
return s*w;
}
int n,m;
int v[MAXN],w[MAXN],f[MAXN][110];
int main(){
cin>>n>>m;
for(int i=1;i<=n;i++){
cin>>v[i]>>w[i];
}
for(int i=1;i<=n;i++){
for(int j=0;j<=m;j++){
for(int k=0;k<=j/v[i];k++){
f[i][j]=max(f[i][j],f[i-1][j-k*v[i]]+w[i]*k);
}
}
}
cout<<f[n][m];
return 0;
}
时间复杂度 \(O(n^3)\)
方法二:
\(f_{[i,j]}=max(f_{[i-1,j]},f_{[i,j-v[i]]}+w_i)\)
代码:
#include<iostream>
#include<cstdio>
#define MAXN 110
using namespace std;
inline int read(){
int s=0,w=1;
char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')w=-1;ch=getchar();}
while(ch>='0'&&ch<='9') s=s*10+ch-'0',ch=getchar();
return s*w;
}
int n,m;
int v[MAXN],w[MAXN],f[MAXN][110];
int main(){
cin>>n>>m;
for(int i=1;i<=n;i++){
cin>>v[i]>>w[i];
}
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++){
f[i][j]=f[i-1][j];
if(j>=v[i]) f[i][j]=max(f[i][j],f[i][j-v[i]]+w[i]);
}
}
cout<<f[n][m];
return 0;
}
时间复杂度 \(O(n^2)\)
方法三:
降维
动态转移方程:
\(f_j=max(f_j,f_{j-c[i]}+w_i)\)
补充:
给定n个物品,其中第i个物品的体积为\(V_i\),价值为\(W_i\),并且有无数个,有一容积为M的背包将物品放入背包,每放入一个物品,就会获得\(A_i*买的个数+B_i\)个糖果,求最后最多能获得多少个糖果
方法一:
\(f_{[i,j,0]}=max(f_{[i-1,j,0]},f_{[i-1,j,1]})\)
\(f_{[i,j,1]}=max(f_{[i,j-w[i],0]}+A_i+B_i,f_{[i,j-w[i],1]}+A_i)\)
方法二:
for i=1 to n
for j=v to w[i]
f[j]=max(f[j],f[j-w[i]]+a[i]+b[i]) //01背包
for j=w[i] to V
f[j]=max(f[j],f[j-w[i]]+a[i]) //完全背包
ICtiger's Blog
求关注
$e^{ix}=cosx+isinx$