背包DP——背包九讲笔记 咕

材料网址:
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;
}

注意,此操作改变了数组的意义!
数组的意义对于做题很重要,帮助你考虑怎么用
这个骚操作把原先的
f [ i ] [ ] f[选入前i个物品][背包的大小]
改成了
f [ ] f[背包的大小]能容纳的最多价值

如果考虑装满背包,无法装满就无解的情况
考虑赋 f [ 0 ] = 0 , f [ i ] = ( i 0 ) f[0]=0,\quad f[i]=-\infin (i\neq 0)
if(f[n]==-INF)printf(“no solution\n”);

另有优化方式:排序后优化,一旦不满足某些条件,后面的就一定都不满足,直接舍掉

T2 小A点菜

真是玄学
f [ j ] = f [ j ] + f [ j a [ i ] ] f[j]=f[j]+f[j-a[i]]
实际上你会发现,T1的优化是一个数组降维的方法很妙哦
不降维,我们可以推得 f i , j = f i 1 , j + f i 1 , j a i f_{i,j}=f_{i-1,j}+f_{i-1,j-a_{i}} 因为 f i , j f_{i,j} 可以由选i-1个菜时选或不选第i个菜品得到
利用遍历n次数组,可以舍去i那一维(需保证遍历时从后往前,因为我们需要的是更新前的 f i 1 , j a i f_{i-1,j-a_{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背包的扩展
f i , j = m a x { f i 1 , j k × c o s t [ i ] + k × v a l u e [ i ] } , 0 < = k × c o s t [ i ] < = j f_{i,j}=max\{ f_{i-1,j-k\times cost[i]}+k\times value[i] \},0<=k\times cost[i]<=j

发布了26 篇原创文章 · 获赞 3 · 访问量 902

猜你喜欢

转载自blog.csdn.net/Antimonysbguy/article/details/103427905