0-1背包问题

背包问题(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









  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值