从零开始-Machine Learning学习笔记(9)-动态规划01背包算法的python实现

​ 这里我先引用dd大牛的背包九讲中关于01背包算法的讲解。

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

​ 这是最基础的背包问题,特点是:每种物品仅有一件,可以选择放或不放。

情况一: 第i件不放进去,这时所得价值为:f[i-i][v]

情况二: 第i件放进去,这时所得价值为:f[i-1][v-c[i]]+w[i]

​ 其状态转移方程为:

f [ i ] [ v ] = m a x { f [ i 1 ] [ v ] , f [ i 1 ] [ v c [ i ] ] + w [ i ] }

​ 这个方程非常重要,基本上所有跟背包相关的问题的方程都是由它衍生出来的。所以有必要将它详细解释一下:“将前i件物品放入容量为v的背包中”这个子问题,若只考虑第i件物品的策略(放或不放),那么就可以转化为一个只牵扯前i-1件物品的问题。如果不放第i件物品,那么问题就转化为“前i-1件物品放入容量为v的背包中”,价值为f[i-1][v];如果放第i件物品,那么问题就转化为“前i-1件物品放入剩下的容量为v-c[i]的背包中”,此时能获得的最大价值就是f[i-1][v-c[i]]再加上通过放入第i件物品获得的价值w[i]。

典型的背包算法:

def deploy_01bag(count_all, capacity, goods):
    '''
    典型01背包算法
    :param count_all:   int, 输入的物品总数
    :param capacity:    int, 背包的容量
    :param goods:       list, 用于装包的物品参数list[[物品的id,物品占据的容量,
                            物品的价值],[],[]...]
    :return:            返回装包方式,list[物品id1,物品id2,...]  最大价值 int
    '''

    bag = [[0 for col in range(capacity + 1)] for raw in range(count_all + 1)]
    result = []
    # 计算背包问题
    for i in range(1, count_all + 1):
        for j in range(1, capacity + 1):
            bag[i][j] = bag[i - 1][j]
            if j >= goods[i - 1][1]:
                bag[i][j] = max(bag[i][j], bag[i - 1][j - goods[i - 1][1]] + goods[i - 1][2])

    # 递推出装入背包的物体
    big = bag[i][j]
    j = capacity
    for i in range(count_all, 0, -1):
        if bag[i][j] > bag[i - 1][j]:
            result.append(goods[i - 1][0])
            j = j - goods[i - 1][1]

    return result, big

if __name__ == "__main__":
    capacity = 10
    goods = [[1, 2, 6],\
             [2, 2, 3],\
             [3, 6, 5],\
             [4, 5, 4],\
             [5, 4, 6]]

    result, big = deploy_01bag(len(goods), capacity, goods)

    print("背包最能装下的最大价值为:{0}\n装包的物品有:{1}".format(big, result))

输出结果为:

背包最能装下的最大价值为:15
装包的物品有:[5, 2, 1]

再举个例子:

​ 举一个具体的例子,在2018年的华为软件精英挑战赛中,给出的题目是预测未来某段时间的虚拟机的使用数量,并给出部署方案,使得每台物理服务器的资源占用率最大。其中物理服务器资源主要有两种。一种那是CPU,另一种是MEM(内存),且其值是固定的。要求优化CPU时,要使CPU的资源占用率最大,且还要满足放入的虚拟机的总的MEM不得超过物理服务器的MEM。

​ 这样,这里的部署问题就是一个背包问题。但是跟01背包问题还有点区别。其中01背包问题是给定容量,使放置的价值总和最大。但是这个大小是没有限制的。但是,在这个问题中。如果我们要优化CPU,那么背包的总的容量就是物理服务器的MEM大小,我们的优化目的是使CPU(价值)最大,且这个最大值不能超过物理服务器的CPU值。

​ 所以我们在进行背包迭代的时候,还需在循环中判断价值不能超过某一固定值。

def deploy_flavor_use_01bag(count_all, predict, server_CPU, server_MEM, target):
    """
    01背包算法装包
    :param count_all:   int 输入的虚拟机总数
    :param predict:     list[list,list...] [型号,CPU,MEM]将每种虚拟机的型号参数数目写出来,
                            如[[10, 8, 8], [10, 8, 8], [10, 8, 8], [7, 4, 4], [7, 4, 4], \
                            [7, 4, 4], [7, 4, 4], [7, 4, 4], [7, 4, 4]]
    :param server_CPU:  int 物理服务器的CPU大小
    :param server_MEM:  int 物理服务器的Memory的大小
    :param target:      int 优化类型 1:CPU, 0:MEM
    :return:            list[list, list...] 每台物理服务器的装包方式  int 每台服务器最大装包结果
    """
    if target:
        server = server_MEM
        limit_factor = server_CPU
        capacity = 2 #every MEM
        weight = 1 #every CPU
    else:
        server = server_CPU
        limit_factor = server_MEM
        capacity = 1 #every CPU
        weight = 2 #every MEM
    bag = [[0 for col in range(server + 1)] for raw in range(count_all + 1)]
    result = []
    # 计算背包问题
    for i in range(1, count_all + 1):
        for j in range(1, server + 1):
            bag[i][j] = bag[i - 1][j]
            if j >= predict[i - 1][capacity]:
                bag[i][j] = max(bag[i][j], bag[i - 1][j - predict[i - 1][capacity]] + predict[i - 1][weight])
            if bag[i][j] > limit_factor:
                n = j - 1
                for m in range(i, 0, -1):
                    if bag[m][n] > bag[m - 1][n]:
                        result.append(predict[m - 1][0])
                        n = n - predict[m - 1][capacity]
                return result, bag[i][j - 1]

    # 递推出装入背包的物体
    big = bag[i][j]
    j = server
    for i in range(count_all, 0, -1):
        if bag[i][j] > bag[i - 1][j]:
            result.append(predict[i - 1][0])
            j = j - predict[i - 1][capacity]

    return result, big

最后再通过反推,将放置方案给输出出来。

更多的算法实现,参见的我的Github,如果觉得有用请别忘了点个Star哟~~~

参考blog:

01背包问题(动态规划)python实现

dd大牛的背包九讲-背包问题汇总

背包之01背包、完全背包、多重背包详解

猜你喜欢

转载自blog.csdn.net/kabuto_hui/article/details/80062880