0-1多背包带约束问题(MKAR)

本文其实与智能算法无关,这是最优化课程的一个小作业,之所以放在智能算法一栏,是因为这个问题的大部分解法都是智能算法。下面出场的是背包问题的一个变种——带约束的多背包问题,这个问题的精确算法复杂度极高,所以一般退而求其次寻找拥有固定近似比的近似算法,本文求解采取的则是一种基于DP动态规划的近似算法,巧妙的并不是算法本身,算法也不能保证求出最优解,精华在于近似比的证明部分,这一部分证明我参考了相关文献,分享给大家细细品味。

❖ 问题描述


有个物品,每个物品的重量为wi,另有m个背包,每个背包的容量为cj,另外每个物品有放入限制R,R_{ij}=1则表明物品i可以放入背包j中,R_{ij}=0则不能,因此R是一个n*m的矩阵。

那么在不违背放入限制规则,同时每个背包内物品不超过相应容量时,如何使背包所装物品的重量最大?上述问题可以用以下数学模型来描述:

\begin{array}{c} \quad \max \sum\limits_{i=1}^{n} \sum\limits_{j=1}^{m} x_{i j} \cdot w_{i} \\ \text { s.t. }\left\{\begin{array}{ll} \sum_{j=1}^{m} x_{i j} \leq 1 & \forall i \in\{1,2, \cdots, n\} \\ \sum_{i=1}^{n} x_{i j} \cdot w_{i} \leq c_{j} & \forall j \in\{1,2, \cdots, m\} \\ x_{i j} \leq R_{i j} & \forall i \in\{1,2, \cdots, n\}, \forall j \in\{1,2, \cdots, m\} \\ x_{i j} \in\{0,1\} & \forall i \in\{1,2, \cdots, n\}, \forall j \in\{1,2, \cdots, m\} \end{array}\right. \end{array}

❖ 算法描述


  1. 设置是否放入标记列表isPut,初始化为False

  2. 依次遍历每一个背包,记当前背包的编号为

  3. 枚举出当前isPut=FalseR[i][j]=1的所有物品集item

  4. 利用DP动态规划求出从item中取出物品放入背包的最优解,并将取出物品的isPut标记为True(f[i,j]表示前i个物品能放入容量为j背包的最大重量) 

    f[i,j]=\max(f[i-1,j],f[i-1,j-w_i]+w_i)
  5. 回到step 1求解下一背包

❖ 近似比证明


上述算法求得的目标函数值T\geq \frac{1}{2}T_{opt}.

Prove

我们假设上述算法执行的目标结果为T,且背包中的物品重量之和为Wj,而该算法中没有被放置于任何背包的物品集为M,接下来证明其余任何可行解从M中取出放入背包的物品重量总和S≤T。

【反证法】 假设存在一个可行解,使得S>T,那么总有一个背包内的物品重量之和>Wk,即背包k里面存在一个物品集I\subset M\sum_{i\in I}w_i>W_k。注意到DP动态规划求得的是最优解,即Wk是当时剩下物品放入背包k的最优方案,而M中的物品在上述算法中没有被放入任何背包,从而可以将I中物品放入背包获得更优解,矛盾!从而S≤T得证。

另外从M外放入背包的物品总量最多即为T,从而背包总量≤T+S≤2T。

❖ 求解结果


背包放入物品编号背包内物品重量之和背包容量
02, 5, 6, 11, 12, 13866866
13, 14, 16, 19, 20, 22908908
21, 7, 10, 18, 21, 24, 30, 3113611361
34, 9, 15, 17, 23, 26, 33559559
48, 27, 28, 32, 36, 39, 40, 42, 47, 4912161216
529, 35, 38, 41, 51, 52983983
625, 34, 37, 53, 54, 5511111111
771, 72, 80, 83300300
846, 50, 56, 57, 63857857
944, 48, 58, 61, 62, 64, 7014621462

问题Sample下载: 多背包问题.

所有背包均装满,可以确定是最优解。

❖ 总结


事实上根据证明过程可以看出,任意一个能够求出0-1单背包问题最优解的算法都可以替换DP算法达到1/2的下界。同时可以举例证明1/2是最优下界,如背包容量{C+ε,C},物品重量为{ε,C,C+ε}。最优解为2C+ε,而实际运行结果可能为C+ε,两者比值\lim_{\epsilon/C\rightarrow0}\frac{C+\epsilon}{2C+\epsilon}=\frac{1}{2}

由此可见,如果将物品重量从高到低排列后再进行DP求解可以优化算法结果。

❖ C ☺ D E


import numpy as np
import pandas as pd
from copy import deepcopy as dp

load = np.array(pd.read_excel("背包问题.xlsx", header=4, usecols=range(1, 11)))
value = np.array(
pd.read_excel("背包问题.xlsx", header=4, usecols=[11]).iloc[:,
    0])
size = np.array(
pd.read_excel("背包问题.xlsx", usecols=range(1, 11), nrows=1).iloc[0, :])

isPut = [False] * len(value)
total = []
list = []
for i in range(len(size)):
    item = []
    for j in range(len(value)):
        if not isPut[j] and load[j, i] == 1:
            item.append(j)
    f = np.zeros([len(item), size[i] + 1])
    it = [[[] for a in range(size[i] + 1)] for b in range(len(item))]
    for a in range(1, len(item)):
        for b in range(value[item[a]], size[i] + 1):
            if value[item[a]] + f[a - 1, b - value[item[a]]] > f[a - 1, b]:
                f[a, b] = value[item[a]] + f[a - 1, b - value[item[a]]]
                it[a][b] = dp(it[a - 1][b - value[item[a]]])
                it[a][b].append(item[a])
            else:
                f[a, b] = f[a - 1, b]
                it[a][b] = dp(it[a - 1][b])
    for k in it[len(item) - 1][size[i]]:
        isPut[k] = True
    if len(item) > 0:
        total.append(f[len(item) - 1, size[i]])
        list.append(it[len(item) - 1][size[i]])

PutIn=pd.DataFrame(columns=range(10),index=range(100))
PutIn.fillna(0,inplace=True)
for i in range(len(list)):
    for j in list[i]:
        PutIn[i][j]=1

print(PutIn)

❖ References


  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值