完全背包问题


01背包问题

01背包问题是最基本的背包问题,在背包9讲里面是怎么描述这个问题的呢?

有N件物品和一个容量为V的背包。第i件物品的费用是c[i],价值是w[i]。
求解将哪些物品装入背包可使价值总和最大。

这个问题里面物品是不能重复的

所以对于这样的问题称为01背包问题,也是对于第i个物品到底是选择(1)还是不选择(0)的问题。

动态规划的思路做的话,可以用Top-Down和Bottom-Up的两种思路,不过逻辑都是一样的。

看一下递归公式

𝑓[𝑖][𝑗]=𝑚𝑎𝑥𝑓[𝑖−1][𝑗],𝑓[𝑖−1][𝑗−𝑐[𝑖]]+𝑤[𝑖]

公式可以拆分成两项:

第一项,不选择c[i],那么直接采用前 𝑖−1 物品时候的结果(最优子问题)

𝑓[𝑖][𝑗]=𝑓[𝑖−1][𝑗]

第二项,如果选择了c[i],那么就会选择前i-1个的最优解和目前结果相加。

𝑓[𝑖][𝑗]=𝑓[𝑖−1][𝑗−𝑐[𝑖]]+𝑤[𝑖]

当然最后需要取这两项的最大值

下面主要是两个版本的代码

0-1 Knapsack Problem | DP-10 - GeeksforGeeks​www.geeksforgeeks.org/0-1-knapsack-problem-dp-10/​编辑

Top-Down

# A naive recursive implementation 
# of 0-1 Knapsack Problem 
  
# Returns the maximum value that  
# can be put in a knapsack of  
# capacity W 
def knapSack(W, wt, val, n): 
  
    # Base Case 
    if n == 0 or W == 0 : 
        return 0
  
    # If weight of the nth item is  
    # more than Knapsack of capacity W,  
    # then this item cannot be included  
    # in the optimal solution 
    if (wt[n-1] > W): 
        return knapSack(W, wt, val, n-1) 
  
    # return the maximum of two cases: 
    # (1) nth item included 
    # (2) not included 
    else: 
        return max( 
            val[n-1] + knapSack( 
                W-wt[n-1], wt, val, n-1),  
                knapSack(W, wt, val, n-1)) 
  
# end of function knapSack 
  
# To test above function 
val = [60, 100, 120] 
wt = [10, 20, 30] 
W = 50
n = len(val) 
print knapSack(W, wt, val, n) 
  
# This code is contributed by Nikhil Kumar Singh 

Bottom-Up

# A Dynamic Programming based Python  
# Program for 0-1 Knapsack problem 
# Returns the maximum value that can  
# be put in a knapsack of capacity W 
def knapSack(W, wt, val, n): 
    K = [[0 for x in range(W + 1)] for x in range(n + 1)] 
  
    # Build table K[][] in bottom up manner 
    for i in range(n + 1): 
        for w in range(W + 1): 
            if i == 0 or w == 0: 
                K[i][w] = 0
            elif wt[i-1] <= w: 
                K[i][w] = max(val[i-1]  
+ K[i-1][w-wt[i-1]],  K[i-1][w]) 
            else: 
                K[i][w] = K[i-1][w] 
  
    return K[n][W] 
  
# Driver program to test above function 
val = [60, 100, 120] 
wt = [10, 20, 30] 
W = 50
n = len(val) 
print(knapSack(W, wt, val, n)) 
  
# This code is contributed by Bhavya Jain 

完全背包问题

有N种物品和一个容量为V的背包,每种物品都有无限件可用。
第i种物品的费用是c[i],价值是w[i]。
求解将哪些物品装入背包可使这些物品的费用总和不超过背包容量,且价值总和最大。

这个问题和上面问题的唯一区别就是在取物品的时候,不再是唯一的(01)的了,而可以是无限制的。

看了网上的一些思路,始终不太明白,为什么第二项从 𝑓[𝑖−1][𝑗−𝑐[𝑖]] 变成了 𝑓[𝑖][𝑗−𝑐[𝑖]] 之后,01背包问题就变成了完全背包问题。

𝑓[𝑖][𝑗]=𝑚𝑎𝑥𝑓[𝑖−1][𝑗],𝑓[𝑖−1][𝑗−𝑐[𝑖]]+𝑤[𝑖] (01背包问题)

𝑓[𝑖][𝑗]=𝑚𝑎𝑥𝑓[𝑖−1][𝑗],𝑓[𝑖][𝑗−𝑐[𝑖]]+𝑤[𝑖] (完全背包问题)

下面是我的解释:

在完全背包问题里,左右都是f[i],所以随着j的增加,f[i][j]是可以通过f[i][j - c[i]]来累加c[i]的。

这里最简单的是f[i] = f[i] + n这个公式可以不断循环

for i in range(n):

f(i) = f(i) + n

可知道f(n) = n^2,所以每次都累加n

如果右边不是f(i)那么就没办法累加,而是每次都算一下f[i][j]相比于f[i-1][j]增加了多少。

而在01问题里面,f[i][j]在j只能选择一个c[i],因为f[i - 1][j - c[i]]是前i - 1项物品c[1]...c[i - 1]的最优子问题。

这里可以举一个最简单的列子(完全背包问题)

对于商品(2, 2,0)(1,5,1)(重量,价值,i) W=10

在计算f[1]的时候,可以知道f[1]=0,2,2,4,4,6,6,8,8,10

在计算f[2][2]的时候,可以知道f[2][1]=5

而这个时候,f[2][2]如果还是取i-1的话,每次都只可以取2,不能够在自身的基础上累加。

如果取f[i]就可以每次对自身进行累加f[2][2] = 5 + 5(此时已经去了两次)

最终的f[2]=5,10,15,20,25...


空间复杂度的简化

对于上面的01背包问题,可以得知,其空间复杂度是 (物品数量X限定容量)

对于完全背包问题也一样

所以为了将空间复杂度简化成o(限定容量)

在01背包问题中,取得f[j]就必须是f[j - 1],如果是顺序的方法去取得话,那么f[j]保存的一定是f[j - c[j]]这个一维数组里面的值一定会被取代成f[i][j - c[i]],所以逆向的话,f[j]每次都是取小的f[j-c[i]],都会取到以前的结果。

for i=1..N
    for j=V..0
        f[j]=max{f[j],f[j-c[i]]+w[i]};

同理,在完全背包问题中,f[j]应该每次都取到的是f[i][j - c[i]]的值。只有是顺序的情况。

完结!

```python
class BertPooler(nn.Module):
    def __init__(self, config):
        super().__init__()
        self.dense = nn.Linear(config.hidden_size, config.hidden_size)
        self.activation = nn.Tanh()

    def forward(self, hidden_states):
        # We "pool" the model by simply taking the hidden state corresponding
        # to the first token.
        first_token_tensor = hidden_states[:, 0]
        pooled_output = self.dense(first_token_tensor)
        pooled_output = self.activation(pooled_output)
        return pooled_output
from transformers.models.bert.configuration_bert import *
import torch
config = BertConfig.from_pretrained("bert-base-uncased")
bert_pooler = BertPooler(config=config)
print("input to bert pooler size: {}".format(config.hidden_size))
batch_size = 1
seq_len = 2
hidden_size = 768
x = torch.rand(batch_size, seq_len, hidden_size)
y = bert_pooler(x)
print(y.size())
```

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值