Python解决 0-1背包问题-实验贪心算法-动态规划等

1.题目内容

题名为:0-1背包问题。
题目要求:
动态规划:
1.用动态规划法设计0-1背包问题的算法,并且对给定的加权数据进行验证。要求分析算法时间复杂性并且形成分析报告。

2.算法分析

动态规划

1.算法原理

依次把每一件物品都放入背包,当背包可容纳值大于等于当前物品重量,与之前可容纳物品的总价值进行对比,如果超出容量,则不换,没有超出换。

2.实现步骤

创建一个value[i][j]数组,表示在面对第 i 件物品,且背包容量为 j 时所能获得的最大价值,
1)当j < w[i] 的情况,这时候背包容量不足以放下第 i 件物品,只能选择不拿
Value[ i ][ j ] = value[ i-1 ][ j ]
2)当j>=w[i] 的情况,这时背包容量可以放下第 i 件物品,我们就要考虑拿这件物品是否能获取更大的价值。如果拿,则value[ i ][ j ]=value[ i-1 ][ j-w[ i ] ] + v[ i ]

3.算法时间复杂性

N 物品数量 可以自定义
C 书包能承受的重量 可以自定义
W 每个物品的重量 随机生成
V 每个物品的价值 随机生成
N C time
5 10 0.0000768
10 10 0.0001398
50 60 0.00222469999
100 150 0.00844489999

4.调试

发现一个很有意思的现象,如果我们用原始的递归办法去做,即排列组合的方法去做时时间复杂度为O(2^N);
当V很大,N较小时,比如V=1000,N=6时,用递归只用计算2^6=64次,而动态规划就需要计算1000*6=6000次

所以说,算法没有绝对的好坏,关键要看应用的惨景

5.代码

import time
import random
def bag(n, c, w, v):
    value = [[0 for j in range(c + 1)] for i in range(n + 1)]
    for i in range(1, n + 1):
        for j in range(1, c + 1):
            if j < w[i - 1]:
                value[i][j] = value[i - 1][j]
            else:
                value[i][j] = max(value[i - 1][j], value[i - 1][j - w[i - 1]] + v[i - 1])
        # 背包总容量够放当前物体,取最大价值
    return value
def show(n, c, w, value):
    print('最大价值为:', value[n][c])
    x = [0 for i in range(n)]
    j = c
    for i in range(n, 0, -1):
        if value[i][j] > value[i - 1][j]:
            x[i - 1] = 1
            j -= w[i - 1]
    print('背包中所装物品为:')
    for i in range(n):
        if x[i]:
            print('第', i+1, '个,', end='')
if __name__=='__main__':
    n=100    #物品数量
    c=150   #书包能承受的重量
    # w = [2, 2, 3, 1, 5, 2]    #每个物品的重量
    w = [random.randint(1,10) for i in range(n)]    #每个物品的重量
    v = [2, 3, 1, 5, 4, 3]    #每个物品的价值
    v = [random.randint(1,10) for i in range(n)]    #每个物品的价值
    t1 = time.perf_counter()
    value = bag(n,c,w,v)
    # print(value)
    show(n, c, w, value)
    t2 = time.perf_counter()
    print()
    print(t2-t1)

贪心算法

1.算法原理

1)贪价值

此算法要的就是价值最大,不需要考虑其他因素,又是达不到最优。

2)贪重量

此算法要的是背包里重量最大,也许会有空间剩余。

3)贪单位重量价值

此算法也到不到整体最优。

2.实现步骤

先创建一个类,把输入的列表转变类对象,带有三个参数。价值,重量,状态。
然后按照每个算法策略不同的要求,排好序,放入背包即可。

3.代码:

3.1背包问题贪心算法-贪单位重量价值量

# 背包问题贪心算法-贪单位重量价值量

class Good:
    def __init__(self, weight, value, status):
        self.weight = weight
        self.value = value
        self.status = status  # 0是未放入背包,1是已经放入背包

class Greedy(object):

    def greedy(self, goods, W):  # goods是物品的集合,W是背包的空闲重量
        result = []
        sum_weight = 0
        ppp = 0
        danjia= 0
        goods.sort(key=lambda obj: obj.value / obj.weight, reverse=True)
        for i in goods:
            if sum_weight + i.weight <= W :
                sum_weight = sum_weight + i.weight
                ppp = ppp + i.value
                danjia = danjia + i.value / i.weight
                result.append(i.weight)

        return result, sum_weight, ppp, danjia




if __name__ == '__main__':
    
    #重量,价值,状态
    goods = [Good(35, 10, 0), Good(30, 40, 0), Good(60, 30, 0), Good(50, 50, 0),
             Good(40, 35, 0), Good(10, 40, 0), Good(25, 30, 0)]
    g = Greedy()
    result, sum_weight,ppp,danjia = g.greedy(goods, 150)
    print("--------------按照取最小重量贪心策略--------------")
    print("最终总价格为:" + str(ppp))
    print("最终总重量为:" + str(sum_weight))
    print("最终总单位价值量为:" + str(danjia))
    print("重量选取依次为:", end='')
    print(result)

3.2 贪价格

# 贪价格
class Good:
    def __init__(self, weight, value, status):
        self.weight = weight
        self.value = value
        self.status = status  # 0是未放入背包,1是已经放入背包

class Greedy(object):

    def greedy(self, goods, W):  # goods是物品的集合,W是背包的空闲重量
        result = []
        sum_weight = 0
        ppp=0
        goods.sort(key=lambda obj: obj.value)
        for i in goods:
            if sum_weight + i.weight <= W :
                sum_weight = sum_weight + i.weight
                ppp = ppp + i.value
                result.append(i.weight)

        return result, sum_weight, ppp

if __name__ == '__main__':
    # goods = [Good(35, 10, 0), Good(30, 40, 0), Good(60, 30, 0), Good(50, 50, 0),]
    #重量,价值,状态
    goods = [Good(35, 10, 0), Good(30, 40, 0), Good(60, 30, 0), Good(50, 50, 0),
             Good(40, 35, 0), Good(10, 40, 0), Good(25, 30, 0)]
    g = Greedy()
    result, sum_weight, ppp= g.greedy(goods, 150)
    print("--------------按照取最小重量贪心策略--------------")
    print("最终总重量为:" + str(sum_weight))
    print("最终价格为:" + str(ppp))
    print("重量选取依次为:", end='')
    print(result)

3.3 贪重量

class Good:
    def __init__(self, weight, value, status):
        self.weight = weight
        self.value = value
        self.status = status  # 0是未放入背包,1是已经放入背包

class Greedy(object):

    def greedy(self, goods, W):  # goods是物品的集合,W是背包的空闲重量
        result = []
        sum_weight = 0
        goods.sort(key=lambda obj: obj.weight)
        for i in goods:
            if sum_weight + i.weight <= W :
                sum_weight = sum_weight + i.weight
                result.append(i.weight)

        return result, sum_weight

if __name__ == '__main__':
    # goods = [Good(35, 10, 0), Good(30, 40, 0), Good(60, 30, 0), Good(50, 50, 0),]
    #重量,价值,状态
    goods = [Good(35, 10, 0), Good(30, 40, 0), Good(60, 30, 0), Good(50, 50, 0),
             Good(40, 35, 0), Good(10, 40, 0), Good(25, 30, 0)]
    g = Greedy()
    result, sum_weight = g.greedy(goods, 150)
    print("--------------按照取最小重量贪心策略--------------")
    print("最终总重量为:" + str(sum_weight))
    print("重量选取依次为:", end='')
    print(result)

3.结果分析

网上说贪心算法不能解决0-1背包问题,得不到最优解。因为它无法保证最终能将背包装满,部分闲置的背包空间使每公斤背包空间的价值降低了。事实上,在考虑0-1背包问题时,应比较选择该物品和不选择该物品所导致的最终方案,然后再作出最好选择。由此就导出许多互相重叠的子问题。这正是该问题可用动态规划算法求解的另一重要特征。

你可能感兴趣的:(算法,python,算法,python,动态规划)