数模笔记:动态规划(背包问题)

基本步骤:

        1、定义原问题和子问题

                原问题:将m件物品放入容量为W的背包中所能获得的最大利润。

                子问题:将前 i(i<=m)件物品选择性的放入容量为 j(j<=W)的背包中所能获得的最大利润。

        2、定义状态函数

                定义状态函数 f(i,j) 表示把i件物品放入 j 大小的背包中所能获得的最大利润。

                则 f(m,W)就是我们要求的结果。

                因为有两个变量,所以DP数组为二维数组。

        3、寻找状态转移方程

                特殊情况(边界条件):

                        i 等于1,只要这一件物品重量(w1)小于背包容量 j ,那么就可以获得这一件物品的利润,即 f(1,j)=v1(第1件物品的利润),否则等于0。

                        j等于1,我们只能选择重量为1的物品放入背包,即 f(i,1)=vi,否则为0。

                一般情况:

                        我们已经安排好了前 i-1 件物品的存放,现在第 i 件物品摆在我们面前。我们只有放和不放两种选择。

                        选择不放(第i件物品甚至大于背包容量),那么问题很简单,f(i,j)=f(i-1,j)。

                        选择放(第i 件物品小于等于背包容量),那么又会出现两种情况。

                                等于:放了第 i 件物品,前面的i-1件物品就塞不下了,那么利润就是vi.

                                小于:放了第 i 件物品,前面的还能塞一点,那么我们是不是可以把问题转化为在 i-1 件物品中挑一些放入容量为 j-wi 的背包中?即此时的利润为 f(i-1,j-wi)。

        4、matlab编程求解(输出选择的物品编号)

                

%来自清风老师
function [f, IND] = knapsack01problem2(p,w,W)
    % 输入: p:物品的利润  w:物品的重量  W:背包的容量
    % 为了编程方便,假设W是大于等于2的正整数;w中每个元素都是大于等于1的正整数
    m = length(p);  % 物品个数
    FF = zeros(m,W);  % 初始化DP数组
    % FF(i,j):前i件物品选择性的放入容量为j的背包中所能获得的最大利润
    if w(1) <= W  % 初始化第一行
        FF(1,w(1):end) = p(1);
    end
    for i = 2:m  % 初始化第一列
        FF(i,1) = max([p(w(1:i) == 1),0]);
    end
    % i,j>1的情况
    for i = 2:m
        for j = 2:W
            if w(i) > j  % 第i件物品的重量w(i)比背包的容量j还要大
                FF(i,j) = FF(i-1,j) ;
            elseif w(i) == j  % 第i件物品的重量w(i)等于背包的容量j
                FF(i,j) = max(FF(i-1,j), p(i));  % 不放进去和放进去取较大的值
            else  % 第i件物品的重量w(i)小于背包的容量j
               FF(i,j) = max(FF(i-1,j), p(i)+FF(i-1,j-w(i)));  % 不放进去和放进去取较大的值
            end
        end
    end
    f = FF(m,W);
    IND = [];  % 选择的物品编号IND初始化为空
    if f > 0   % 只要有利润,就可以利用FF来计算选择的物品编号IND
        ww = W;  % 初始化背包的剩余容量为整个背包的容量W
        tmp = FF(:,ww);  % 取出最后一列
        while 1  % 不断循环下去,后面通过条件判断来退出循环
            ind = find(tmp == max(tmp),1) ;  % 找到装入背包的那个物品
            ww = ww - w(ind);  % 更新背包的剩余容量
            IND = [IND,ind];  % 更新IND里面的元素
            if ind > 1 && ww>0  % 只要不是第一个物品或者背包容量为空
                tmp = FF(1:ind-1,ww);  % 重新取出剩余容量的那一列(只保留前面的物品)
            else
                break   % 跳出循环
            end
        end
        IND = sort(IND);  % 排序下,输出好看点
    end
end

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值