周六900C++班级-2022-11-26-完全背包
完全背包定义
有N种物品和一个容量为V的背包,每种物品都有无限件可用。第i种物品的体积是w[i],价值是v[i]。求解将哪些物品装入背包可使这些物品的费用总和不超过背包容量,且价值总和最大。
从定义中可以看出,与01背包的区别01背包最多只能拿一件物品,完全背包则不然,只要空间够多,一种物品我可以拿n件!
01背包的状态转移方程为:dp(i,j)=max(dp(i-1,j),dp(i-1,j-w[i])+v[i])
完全背包的状态转移方程:dp(i,j)=max(dp(i-1,j),dp(i,j-w)+v[i])
我们可以看出,完全背包的动态转移方程max中第二项为i,而不是i-1。
为什么呢?
我从代码的角度阐释一下这个问题!
注意我们现在并没有对dp数组进行降维!
我们的j是从0开始的,依次递增这个是完全背包的关键,也是与01背包本质的区别
dp[i][j]=max(dp[i-1][j],dp[i][j-w[i]]+v[i]);
首先要满足完全背包的动态转移方程,就要先知道dp(i,j-w)的大小
正好我们是从0开始的,并不是从后往前,也就是当求到dp(i,j)时
dp(i,j-w),在前面已经求过!!!
所以我们可以应当理顺的求出dp(i,j)而不再是向01背包要考虑前i-1时候的状态!
完全背包的优化
然后我们根据01背包的优化原则对,完全背包进行优化!
优化后的动态方程
dp[j]=max(dp[j],dp[j-w]+v)
#include<bits/stdc++.h> using namespace std; int dp[30005]; //dp[j] = 最大容量为j时的最大价值 int n,m; int w[105],v[105];//w重量,v价值 int main() { cin>>m>>n; for(int i=1;i<=n;i++)cin>>w[i]>>v[i]; for(int i=1;i<=n;i++) { for(int j=w[i];j<=m;j++) { //dp[j] = dp[j] , dp[j-w[i]]+v[i] dp[j] = max(dp[j],dp[j-w[i]]+v[i]); } } cout<<dp[m]; return 0; }
完全背包问题
#include<bits/stdc++.h> using namespace std; int n,m; int w[105],v[105],dp[30005]; int main(){ cin>>m>>n; for(int i=1;i<=n;i++)cin>>w[i]>>v[i]; for(int i=1;i<=n;i++){ for(int j=w[i];j<=m;j++){ dp[j]=max(dp[j],dp[j-w[i]]+v[i]); } } printf("max=%d",dp[m]); return 0; }
货币系统
#include<bits/stdc++.h> using namespace std; long long int dp[3005]; //dp[j] = 当面值为j时的最大方案数 int n,m; //n个物品,m容量 int w[20]; //w[i]每个货币的面值 int main() { cin>>n>>m; for(int i=1;i<=n;i++)cin>>w[i]; dp[0] = 1; for(int i=1;i<=n;i++) { for(int j=w[i];j<=m;j++) { dp[j] = dp[j] + dp[j-w[i]]; } } cout<<dp[m]; return 0; }
买书
#include<bits/stdc++.h> using namespace std; int dp[3005]; int m; int w[20] = {0,10,20,50,100}; int main() { cin>>m; dp[0] = 1; //当j-w[i]=0时证明刚好可以购买第i种面值的书 for(int i=1;i<=4;i++) { for(int j=w[i];j<=m;j++) { dp[j] = dp[j] + dp[j-w[i]]; } } cout<<dp[m]; return 0; }
最小乘车费用
#include<bits/stdc++.h> using namespace std; int dp[30005]; int n,m; int w[300],v[300]; int main() {//最小乘车费用5734 memset(dp,9999,sizeof(dp)); dp[0] = 0; n = 10; for(int i=1;i<=n;i++)cin>>v[i]; cin>>m; for(int i=1;i<=n;i++) { for(int j=i;j<=m;j++) { dp[j] = min(dp[j],dp[j-i]+v[i]); } } cout<<dp[m]; return 0; }