0-1背包问题

来源:互联网 发布:淘宝买gtx1080截图 编辑:程序博客网 时间:2024/06/01 08:08

背包问题(Knapsack problem)是一种组合优化的NP完全问题。问题可以描述为:给定一组物品,每种物品都有自己的重量和价格,在限定的总重量内,我们如何选择,才能使得物品的总价格最高。问题的名称来源于如何选择最合适的物品放置于给定背包中。

一般的,0-1背包问题可以描述为1个背包,物品的重量为wi,其价值为vi,背包容量为c。使其价值总量最大。即:

                                                                                  

m(ij)是背包容量为j,可选择物品为ii+1n0-1背包问题的最优值。由0-1背包问题的最优子结构性质,可以建立计算m(ij)的递归式如下:

               

以上是逆序,即从最满状态一个个扔。如下是顺序的递推式:


为节省空间,可以将二维的列表变为一维的,每次循环只需保留相应位置的较大值即可。

0-1背包问题又可以根据是否恰好放满背包,可以分为两类。首先第一类,就是只要价值最大,质量可以不是刚好最大;第二类则是质量刚好最大,而且价值最大。只需要设置不同的初始化条件,便可以实现不同的答案。

1.对于没有要求必须安装背包的情况下,初始化最大值都为0,是不存在非法状态的。因为可以什么都不装。2.但是如果要求恰好装满,则必须区别初始化,即f[0]=0,其他设为一个较大的负数。以下以例题进行讲解:

题目描述:

小白和小红一起逃亡,现在有许多的东西要放在小红的包里面,但是包的大小有限,所以我们只能够往里面放入非常重要的物品。现在给出该种物品的数量、体积、价值的数值,希望你能够算出怎样使背包的价值最大的组合方式,并输出这个值。

输入:

第一行有2个整数,物品种数n和背包装载体积v

第二行到i+1行每行3个整数,为第i种物品的数量m、体积w、价值s

输出:

一个整数,整数表示最大价值。

解析:

这题没有恰好,所以,初始化都为0即可,这里我用两种代码形式表示,一种是逆序的递推,一种顺序的递推:

代码实现:

1.逆序:

#-*-coding:utf-8 -*-while True:    try:        n,v=map(int,raw_input().split())        we,se=[0],[0]        res=[]        t=[]        q=[]        r=0        for i in range(n):            m,w,s=map(int,raw_input().split())            r+=m            we.extend([w]*m)            se.extend([s]*m)        dp=[[0 for i in range(v+1)] for j in range(r+1)]        for j in range(v + 1):            if j >= we[r]:                dp[r][j] = se[r]            else:                dp[r][j] = 0        for i in range(r-1,-1,-1):            for j in range(v+1):                if j<we[i]:                    dp[i][j]=dp[i+1][j]                else:                    dp[i][j]=max(dp[i+1][j],dp[i+1][j-we[i]]+se[i])        print dp[0][-1]    except:        break

顺序:

def solve(v,w,s,n):    r = [0]*(s+1)    r[0]=0    for i in range(1,n+1):        for j in range(s,0,-1):            if w[i] <= j:                r[j] = max(r[j],r[j-w[i]]+v[i])    return r[-1]if __name__ == '__main__':    n,weight=map(int,raw_input().split())    we=[0]    se=[0]    r=0    for i in range(n):        m, w, s = map(int, raw_input().split())        r += m        we.extend([w] * m)        se.extend([s] * m)    result = solve(se,we,weight,r)    print(result)

ps:这两个都在we和se数组最开始加了0,为了平衡数组的下标。

2.假如是恰好呢?

def solve2(v,w,s,n):    r = [-100]*(s+1)    r[0]=0    for i in range(1,n+1):        for j in range(s,0,-1):            if w[i] <= j:                r[j] = max(r[j],r[j-w[i]]+v[i])    return r[-1]if __name__ == '__main__':    n,weight=map(int,raw_input().split())    we=[0]    se=[0]    r=0    for i in range(n):        m, w, s = map(int, raw_input().split())        r += m        we.extend([w] * m)        se.extend([s] * m)    result = solve2(se,we,weight,r)    print(result)

转载请注明:转自http://blog.csdn.net/carson0408/article/details/77825391









原创粉丝点击