材料网址:
https://blog.csdn.net/m0_37809890/article/details/83153974
T1 bone collector
#include<bits/stdc++.h>
using namespace std;
#define in Read()
#define re register
int T;
int n,m;
int val[1010],wei[1010];
int f[1010][1010];
inline int in{
int i=0,f=1;char ch;
while((ch>'9'||ch<'0')&&ch!='-')ch=getchar();
if(ch=='-')ch=getchar(),f=-1;
while(ch>='0'&&ch<='9')i=(i<<1)+(i<<3)+ch-48,ch=getchar();
return i*f;
}
inline void reset(){
n=0,m=0;
memset(val,0,sizeof(val));
memset(wei,0,sizeof(wei));
memset(f,0,sizeof(f));
return ;
}
int main(){
T=in;
while(T--){
reset();
n=in,m=in;
for(re int i=1;i<=n;i++)val[i]=in;
for(re int i=1;i<=n;i++)wei[i]=in;
for(re int i=1;i<=n;i++)
for(re int j=0;j<=m;j++){
if(j>=wei[i])
f[i][j]=max(f[i-1][j],f[i-1][j-wei[i]]+val[i]);
else
f[i][j]=f[i-1][j];
}
printf("%d\n",f[n][m]);
// for(re int i=1;i<=n;i++){
// for(re int j=1;j<=m;j++)
// printf("%d ",f[i][j]);
// printf("\n");
// }
}
return 0;
}
优化空间复杂度
用覆盖的方式,节省f的空间
#include<bits/stdc++.h>
using namespace std;
#define in Read()
#define re register
int T;
int n,m;
int val[1010],wei[1010];
int f[1010];
inline int in{
int i=0,f=1;char ch;
while((ch>'9'||ch<'0')&&ch!='-')ch=getchar();
if(ch=='-')ch=getchar(),f=-1;
while(ch>='0'&&ch<='9')i=(i<<1)+(i<<3)+ch-48,ch=getchar();
return i*f;
}
inline void reset(){
n=0,m=0;
memset(val,0,sizeof(val));
memset(wei,0,sizeof(wei));
memset(f,0,sizeof(f));
return ;
}
int main(){
T=in;
while(T--){
reset();
n=in,m=in;
for(re int i=1;i<=n;i++)val[i]=in;
for(re int i=1;i<=n;i++)wei[i]=in;
for(re int i=1;i<=n;i++)
for(re int j=m;j>=wei[i];j--)
f[j]=max(f[j],f[j-wei[i]]+val[i]);
printf("%d\n",f[m]);
// for(re int i=1;i<=n;i++){
// for(re int j=1;j<=m;j++)
// printf("%d ",f[i][j]);
// printf("\n");
// }
}
return 0;
}
注意,此操作改变了数组的意义!
数组的意义对于做题很重要,帮助你考虑怎么用
这个骚操作把原先的
改成了
如果考虑装满背包,无法装满就无解的情况
考虑赋
if(f[n]==-INF)printf(“no solution\n”);
另有优化方式:排序后优化,一旦不满足某些条件,后面的就一定都不满足,直接舍掉
T2 小A点菜
真是玄学
实际上你会发现,T1的优化是一个数组降维的方法很妙哦
不降维,我们可以推得
因为
可以由选i-1个菜时选或不选第i个菜品得到
利用遍历n次数组,可以舍去i那一维(需保证遍历时从后往前,因为我们需要的是更新前的
)
#include<bits/stdc++.h>
using namespace std;
#define in Read()
#define re register
int n,m,a[110];
int f[10009];
inline int in{
int i=0,f=1;char ch;
while((ch>'9'||ch<'0')&&ch!='-')ch=getchar();
if(ch=='-')ch=getchar(),f=-1;
while(ch>='0'&&ch<='9')i=(i<<1)+(i<<3)+ch-48,ch=getchar();
return i*f;
}
int main(){
n=in,m=in;
for(re int i=1;i<=n;i++)a[i]=in;
f[0]=1;
for(re int i=1;i<=n;i++)
for(re int j=m;j>=a[i];j--){
f[j]+=f[j-a[i]];
}
printf("%d\n",f[m]);
return 0;
}
T3 采药
记错了,我还以为这道题是完全背包
就是0/1
朴素版
#include<bits/stdc++.h>
using namespace std;
#define in Read()
#define re register
int t,m;
int spend[110],val[110];
int f[110][1010];
inline int in{
int i=0,f=1;char ch;
while((ch>'9'||ch<'0')&&ch!='-')ch=getchar();
if(ch=='-')ch=getchar(),f=-1;
while(ch>='0'&&ch<='9')i=(i<<1)+(i<<3)+ch-48,ch=getchar();
return i*f;
}
int main(){
t=in,m=in;
for(re int i=1;i<=m;i++)spend[i]=in,val[i]=in;
for(re int i=1;i<=m;i++)
for(re int j=1;j<=t;j++){
if(spend[i]<=j)
f[i][j]=max(f[i-1][j],f[i-1][j-spend[i]]+val[i]);
else
f[i][j]=f[i-1][j];
}
printf("%d",f[m][t]);
return 0;
}
数组降维优化
#include<bits/stdc++.h>
using namespace std;
#define in Read()
#define re register
int t,m;
int spend[110],val[110];
int f[1010];
inline int in{
int i=0,f=1;char ch;
while((ch>'9'||ch<'0')&&ch!='-')ch=getchar();
if(ch=='-')ch=getchar(),f=-1;
while(ch>='0'&&ch<='9')i=(i<<1)+(i<<3)+ch-48,ch=getchar();
return i*f;
}
int main(){
t=in,m=in;
for(re int i=1;i<=m;i++)spend[i]=in,val[i]=in;
for(re int i=1;i<=m;i++)
for(re int j=t;j>=spend[i];j--)
f[j]=max(f[j],f[j-spend[i]]+val[i]);
printf("%d",f[t]);
return 0;
}
完全背包实际上就是0/1背包的扩展