2、背包九讲之第二讲(完全背包问题)

完全背包问题

完全背包与0/1背包很类似,推导过程和思维也差不多

原题链接:3. 完全背包问题 - AcWing题库

题目描述:

有 N 种物品和一个容量是 V 的背包,每种物品都有无限件可用。

第 i种物品的体积是 vi,价值是 wi。

求解将哪些物品装入背包,可使这些物品的总体积不超过背包容量,且总价值最大。
输出最大价值。

朴素算法代码

首先让我们来看看朴素算法的思想

与0/1背包问题类似,我们第i个物品可以选0个,那么dp[ i,j] = dp[i-1,j];

我们也可以选则1个,2个,3个,…,k个

同样直接算并不是很好算,那我们开始曲线救国,先从前i-1种类物品里面选择,然后再加上第i种物品的选择情况,即 dp[ i -1,j-k*v[i] ] +k * w[ i ],我们不难发现,其实选0个可以与后面的合并,也就是k==0的情况

代码如下

#include

using namespace std;
const int N=1010;

int n,V;
int dp[N][N];
int v[N],w[N];

int main(){
    cin>>n>>V;
  for(int i=1;i<=n;i++)cin>>v[i]>>w[i];
   
  for(int i=1;i<=n;i++){ //控制选前几件
      for(int j=0;j<=V;j++){  //控制当前的体积
          for(int k=0;k*v[i]<=j;k++){
      //max第一是dp[i][j]的原因是有不同的k产生不同的dp[i][j],所以max找到最大的自己
      //max第二个用的是dp[i-1]是因为,我们单独把第i个种类拿出来单独考虑  
       //当k==0时,dp[i][j]  =max(dp[i][j],dp[i-1][j])  所以不需要分开选择
              dp[i][j] = max(dp[i][j],dp[i-1][j-k*v[i]]+k*w[i]);    
          }
      }
  }
  cout<<dp[n][V];
    
    return 0;
}

方程展开优化法

 #include

 using namespace std;
 const int N=1010;

 int n,V;

 int dp[N][N];

int v[N],w[N];

//朴素算法推导优化过程
//将dp[i][j]和dp[i][j-v]展开我们不难发现,dp[i][j-v]与dp[i][j]仅相差一个w[i]
//   dp[i,j] = max(dp[i,j],dp[i-1,j-1v]+1w,dp[i-1,j-2v]+2W,dp[i-1,j-3v]+3w,dp[i-1,j-4v]+4w,....)
//   dp[i,j-v]=max(dp[i,i-v],              dp[i-1,j-2v]+1w,dp[i-1,j-3v]+2w,dp[i-1,j-4v]+3w,....)
//综上可得出新的方程
//   dp[i,j] = max(dp[i,j],dp[i,j-v]+w);
 

int main(){
     cin>>n>>V;
   for(int i=1;i<=n;i++)cin>>v[i]>>w[i];
   
   for(int i=1;i<=n;i++){ //控制选前几件
       for(int j=0;j<=V;j++){  //控制当前的体积
       //优化完后要考虑选与不选两种情况
       //优化前的代码没考虑是因为不选的情况也包含在里面了,就是k==0时的情况
       dp[i][j] = dp[i-1][j];
        if(j>=v[i]) dp[i][j] = max(dp[i][j],dp[i][j-v[i]]+w[i]);
       }
   }
   cout<<dp[n][V];
    
     return 0;
 }

优化为一维

#include
using namespace std;
const int N=1010;

int n,V;
int dp[N];
int v[N],w[N];

int main(){
    cin>>n>>V;
  for(int i=1;i<=n;i++)cin>>v[i]>>w[i];
   
  for(int i=1;i<=n;i++){ //控制选前几件
      for(int j=v[i];j<=V;j++){  //控制当前的体积
         //因为这次二维我们使用的是dp[i][j-v[i]],用的是i层而不是i-1层,所以我们不需要倒叙遍历,正序即可
         dp[j] = max(dp[j],dp[j-v[i]]+w[i]);
      }
  }
  cout<<dp[V];
    
    return 0;
}

你可能感兴趣的:(c++,#背包九讲,算法)