DP之完全背包问题

完全背包:

Such as设有n种物品,每种物品有一个重量及一个价值。但每种物品的数量是无限的,同时有一个背包,最大载重量为M,今从n种物品中选取若干件(同一种物品可以多次选取),使其重量的和小于等于M,而价值的和为最大

 

对于这个问题,啊,还是直接上代码吧,在代码中理解,

解一:

只需在01背包上稍稍改善以下就行

 

#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;
int main()
{
    int dp[20][20],x[20];
    int v[]={0,8,10,6,3,7,2}; ///为便于读者阅读,初始化
    int w[]={0,4,6,2,2,5,1};
    int n=6,c=12;

    memset(dp,0,sizeof(dp)); ///小提醒:只能赋0,或-1
    for(int i=1;i<=n;i++)  ///从第1个到第i个物品中挑选出总重量不超过j的物品时总价值的最大值
    {
        for(int j=1;j<=c;j++)
        {
        for(int k=1;k*w[i]<=j;k++){ ///跟01背包就只多了这一句,应该都很好理解,这里就不多解释了。
                dp[i][j]=max(dp[i-1][j],dp[i-1][j-k*w[i]]+k*v[i]);
            }
        }
    }
    printf("%d\n",dp[n][c]); ///总价值
   return 0;

}

解二:

这样写的的程序有三重循环,显然复杂度有点大哦,其实我们还可以优化,怎么优化呢?看这里,我们在dp[i][j]的计算中选择k(k>=1)个的情况,与在dp[i+1][j-w[i]]的计算中选择k-1个的情况是一样的,,这样我们就不需要k变量循环语句了,所以我们就可以这样敲:

dp[i][j]=max(dp[i-1][j],dp[i][j-w[i]]+v[i]);      k-1个

dp[i][j-w[i]]=max(dp[i-1][j],dp[i][j-2*w[i]]+2*v[i]);    k-2个此次其实已经在k-1个之前算出来了(因为j是从1到c的,k-2个的j-2*w[i]值是不是肯定小于k-1个的j-w[i]的值,所以就能很好的解释为什么k-2个在k-1个之前已经算出来了),我们就是通过这样类似于解法1的循环去解出来的,紧接着还有k-3个,也在k-2个之前已经求出来了,以此类推,直到k-n==1次结束。自己细想下就能明白的。

#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;
int main()
{
    int dp[20][20],x[20];
    int v[]={0,8,10,6,3,7,2}; ///为便于读者阅读,初始化
    int w[]={0,4,6,2,2,5,1};
    int n=6,c=12;

    memset(dp,0,sizeof(dp)); ///小提醒:只能赋0,或-1
    for(int i=1;i<=n;i++)  ///从第1个到第i个物品中挑选出总重量不超过j的物品时总价值的最大值
    {
        for(int j=1;j<=c;j++)
        {
                ///此句与01背包中dp[i][j]=max(dp[i-1][j],dp[i-1][j-w[i]]+v[i]);
                ///有区别哦,注意比较理解
                if(j<w[i]) dp[i-1][j];
               else  dp[i][j]=max(dp[i-1][j],dp[i][j-w[i]]+v[i]);

        }
    }
    printf("%d\n",dp[n][c]); ///总价值
   return 0;

}



 

 

 

 

 

 

 

 


### 完全背包问题的闫氏动态规划解析 #### 动态规划的核心思想 完全背包问题是经典的组合优化问题之一,其目标是在给定容量 \(V\) 的背包中放入若干物品,使得总价值最大化。与01背包不同的是,每种物品可以被无限次选取。 闫氏动态规划方法通过状态转移方程定义了一个清晰的状态表示方式,并利用滚动数组优化了空间复杂度。以下是具体实现和解析: --- #### 状态定义 设 \(dp[j]\) 表示当前状态下,背包容量为 \(j\) 时所能获得的最大价值。对于第 \(i\) 种物品,其体积为 \(v[i]\),价值为 \(w[i]\)[^3]。 初始条件:\(dp[0]=0\), 即当背包容量为0时,最大价值也为0。 --- #### 转移方程 在处理第 \(i\) 种物品时,考虑将其加入背包的情况,则状态转移方程为: \[ dp[j] = \max(dp[j], dp[j-v[i]] + w[i]) \] 其中,\(dp[j-v[i]] + w[i]\) 表示将一件该物品放入背包后的新增价值[^4]。 注意,在遍历过程中,为了允许同一种物品多次选入背包,第二层循环需从小到大进行迭代。这与01背包中的逆序遍历形成鲜明对比。 --- #### 时间与空间复杂度 时间复杂度为 \(O(N \times V)\),其中 \(N\) 是物品数量,\(V\) 是背包容量;而经过一维数组的空间压缩后,空间复杂度降为 \(O(V)\)[^1]。 --- #### Python代码实现 下面是基于上述理论的具体Python代码实现: ```python def complete_pack(v, w, capacity): n = len(v) dp = [0] * (capacity + 1) for i in range(n): # 遍历每一个物品 for j in range(v[i], capacity + 1): # 对于每个可能的重量,正向更新 if j >= v[i]: dp[j] = max(dp[j], dp[j - v[i]] + w[i]) return dp[capacity] # 测试数据 values = [6, 3, 5] # 物品价值列表 weights = [2, 1, 3] # 物品重量列表 bag_capacity = 5 # 背包的容量 result = complete_pack(weights, values, bag_capacity) print(f"Maximum value achievable is {result}") ``` 此代码实现了完全背包问题的基础逻辑,能够计算出满足约束条件下最大的物品价值[^2]。 --- #### 解析总结 通过对闫氏DP分析法的理解可以看出,完全背包的关键在于如何设计合理的状态转移关系以及控制嵌套循环的方向。相比01背包而言,虽然两者形式上接近,但在实际操作层面存在细微差异——尤其是关于重复取物这一点的设计思路决定了它们各自独特的解决方案。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值