python

来源:互联网 发布:ipadmini2怎么下载软件 编辑:程序博客网 时间:2024/06/16 08:55

动态规划:

0-1背包问题,替换问题,解不唯一

找到最优子结构和重叠子问题,进而找到状态转移方程

最优子结构保证每个状态是最优的;

重叠子问题也即n状态的求法和n-1状态的求法是一样的;

实现上一般是根据状态转移方程自底向上的迭代求得最优解(也可以使用递归自顶向下求解)。

二维数组(状态转移矩阵)dp[i][j]来记录各个子问题的最优状态,其中dp[i][j]表示前i个物体面对容量j背包的最大价值

最优解是在面对每个物体时选择能够最大化背包价值的状态。

0-1背包的状态转移方程为
f(i,v) = max{ f(i-1,v), f(i-1,v-c[i])+w[i] }

----------

输入:两个数列,长度为N,一个是重量,一个是对应的单价;每种物品只能选择0个或1个。

输出:在限定的总重量范围内,得出最大的价格组合,将选中的物品放入背包,没选中的丢弃。

例:

ID:[0,1,2,3,4,5]

重量:[5,4,6,3,2,1]

单价:[1,2,100,3,4,5]

限定重量:9

最优组合:重量[3,2,1]总价格5+8+9=22

重量[6,2,1]总价格600+8+5

---------

直观上的解法是:先挑选一个装包里,再装下一个:

这就是贪婪算法。先按照一定的规则排序,比如按重量、按价格,按密度等,然后从大到小依次选取。

贪婪算法:得到的是局部最优解,不一定是全局最优解。但效率更高,简单。实际应用很多采用该方法。

如果满足条件,就把下一个也装进包里;

如果不满足条件:

丢弃下一个

将下一个与包里的融合进行比较,得出包里新的组合(通过二维数组来展示)

以下这样的实现太难了,找不到程序的着力点:

for i=1到N

    if 背包剩余容量 > 第i个的重量:

        i次的总价格 = 第i-1次的总价格 + 第i个的价格

        背包剩余容量 = 背包剩余容量 - 第i个的重量

    else

        i次的总价格 = 第i-1次的总价格

--------------

实际实现是这样的:

动态规划算法:得到的是最优解。但比较复杂,需要得到状态转移方程。

For row=N-0 反向查找

选取这一行第一次出现最大值的列数COL

将最大值与上一行比较

若相等,该行对应的物品不是选中的物品,列数不变,行数减一

若不相等,记录该行对应的物品,列数-cost(row),行数减一

形成可递归的矩阵:

新行数 = 行数减一

新列数 = COL-1 或 COL -1- cost(row)

递归结束的条件为查找当前递归矩阵的最大值为零。

---------

拓展:

分组背包:

N件物品和一个容量为V的背包。第i件物品的费用是c,价值是w。

这些物品被划分为若干组,每组中的物品互相冲突,最多选一件。

求解将哪些物品装入背包可使这些物品的费用总和不超过背包容量,且价值总和最大。

依赖问题:

这种背包问题的物品间存在某种“依赖”的关系。也就是说,i依赖于j,表示若选物品i,则必须选物品j。

为了简化起见,我们先设没有某个物品既依赖于别的物品,又被别的物品所依赖;

另外,没有某件物品同时依赖多件物品。

---------


-------

源代码:

# encoding:utf-8import osdef bag(weight,cost,max_cost):    '''f(i,v) = max{ f(i-1,v), f(i-1,v-c[i])+w[i] }'''    n = len(cost)    res=[[0 for j in range(max_cost+1)] for i in range(n+1)]    for i in range(1,n+1): # 物品的id0-n        for j in range(1,max_cost+1): # 总容量(一个变化着的量)            res[i][j]=res[i-1][j]            if j>=cost[i-1] and res[i][j] < (res[i-1][j-cost[i-1]] + weight[i-1]):                res[i][j] = res[i-1][j-cost[i-1]] + weight[i-1]    row, col = show_res(res)    return res, res[row][col]def show_res(res):    row = len(res)    for i in range(0,row,1):        col = len(res[i])        print        for j in range(0,col,1):            print res[i][j],    print    return row-1, col-1def show_result(res, cost):    '''从结果往前查找,找到第0列结束'''    global res_id    row, col = show_res(res)    result = res[row][col]    # 递归结束的条件为查找当前递归矩阵的最大值为零    if result == 0:        return 0    row0 = 0    col0 = 0    for i in range(col,0,-1):        if result != res[row][i]:            #选取这一行第一次出现最大值的列数COL            col0 = i+1            # 将最大值与上一行比较            if res[row][i+1] != res[row-1][i+1]:                # 若不相等,记录该行对应的物品,列数-cost(row),行数减一                # print 'cost', row, cost[row-1]                col0 = col0 - cost[row-1]                res_id.append(cost[row-1])            else:                # 若相等,该行对应的物品不是选中的物品,列数不变,行数减一                pass            break    # 形成可递归的矩阵:    # 新行数 = 行数减一    # 新列数 = COL - 1  COL - cost(row) - 1    row_new = row - 1    col_new = col0 - 1    # print row_new, col_new    res0 = []    for i in range(0,row_new+1,1):        res0.append([0]) # 先创建i        for j in range(0,col_new+1,1):            res0[i].append(int(res[i][j+1]))  # 对每行中的数赋值,注意不是res0[i].append(int(res[i][j])),因为已经有了第一列    # show_res(res0)    return show_result(res0, cost)if __name__=='__main__':    max_cost = 10    # cost=[2,2,6,5,4]  # max_cost = 10 result = [4,2,2]    # weight=[6,3,5,4,6]    cost = [5,4,6,3,2,1] # max_cost = 10 result = [6,2,1]    weight = [1,2,100,3,4,5]    # cost = [10,3,4,5]  # max_cost = 10 result = [5,4]    # weight = [3,4,6,7]    res_id = []    res, max_weight = bag(weight,cost,max_cost)    res0 = show_result(res, cost)    # res1 = show_result(res0, cost)    # res2 = show_result(res1, cost)    # res3 = show_result(res2, cost)    # res4 = show_result(res3, cost)    print '符合最大cost限制 %d cost取值为'  % max_cost, res_id, '\nweight最大为 %d' % max_weight'''0 0 0 0 0 0 0 0 0 0 00 0 0 0 0 1 1 1 1 1 10 0 0 0 2 2 2 2 2 3 30 0 0 0 2 2 100 100 100 100 1020 0 0 3 3 3 100 100 100 103 1030 0 4 4 4 7 100 100 104 104 1040 5 5 9 9 9 100 105 105 109 1090 0 0 0 0 0 0 0 0 0 00 0 0 0 0 1 1 1 1 1 10 0 0 0 2 2 2 2 2 3 30 0 0 0 2 2 100 100 100 100 1020 0 0 3 3 3 100 100 100 103 1030 0 4 4 4 7 100 100 104 104 1040 5 5 9 9 9 100 105 105 109 1090 0 0 0 0 0 0 0 00 0 0 0 0 1 1 1 10 0 0 0 2 2 2 2 20 0 0 0 2 2 100 100 1000 0 0 3 3 3 100 100 1000 0 4 4 4 7 100 100 1040 0 0 0 0 0 00 0 0 0 0 1 10 0 0 0 2 2 20 0 0 0 2 2 1000 0 0 3 3 3 1000 0 0 0 0 0 00 0 0 0 0 1 10 0 0 0 2 2 20 0 0 0 2 2 100000符合最大cost限制 10 cost取值为 [1, 2, 6]weight最大为 109'''