完全背包及降维

问题模型
给定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])  //完全背包
posted @ 2021-07-20 10:15  ICtiger  阅读(107)  评论(0)    收藏  举报