zoukankan      html  css  js  c++  java
  • 经典动态规划——背包问题系列一

    经典动态规划——背包问题系列一

    复赛前发一波博客,虽然意义不是很大了……

    本篇讲的是背包问题基础

    01背包问题

    简述

    有N件物品和一个容量为V的背包。第i件物品的体积是c[i],价值是w[i]。求解将哪些物品装入背包可使这些物品的费用总和不超过背包容量,且价值总和最大。

    思路

    动态规划的基本题,背包问题之母。

    对动态规划有一定了解的人应该都应理解它的原理和方程。

    所谓动态规划,就是把问题分成互相联系的多个阶段决策,每一步决策都能影响答案。当然,各个阶段决策的选取不是任意确定的,它依赖于当前面临的状态,又影响以后的发展。那么我们需要确定,各阶段之间的关系是什么以及各状态如何决策才能使答案最优。

    在背包问题中,我们通常把背包容量设为状态。那么我们需要决策,到底如何放置物品,才能使各阶段背包在有限容量内装价值最多的物品?

    首先我们需要知道:背包容量大的状态一定由容量小的状态转移过来,因为我们要不断选物品,这样是总重量越来越大。现在我们用f[i][j]示前i件物品恰放入一个容量为v的背包可以获得的最大价值。

    我们只要枚举物品,在有限的空间里取物品,并一直取max,就能在规定背包空间内跑完。

    [dp[i][v] = max(dp[i-1][v],dp[i-1][v-c[i]]+w[i]) ]

    为什么要逆着枚举?因为容量大的状态要从容量小的状态转移过来,而我们要固定每个容量去装物品,所以要从大到小枚举。

    代码

    for(int i=1;i<=n;i++) 
    	for(int j=v;j>=0;j--)
        {
            if(j >= c[i])
            	dp[i][j]=max(dp[i-1][j-c[i]]+w[i],dp[i-1][j]);
           	else
                dp[i][j] = dp[i-1][j];
        }
    

    优化

    将我们可以优化一维空间,方程就变成了:

    [dp[v] = max(dp[v],dp[v-c[i]] + w[i]) ]

    代码

    for(int j=v;j>=w[i];j--)
    	dp[j] = max(dp[j],dp[j-c[i]]+w[i]);
    

    拓展:背包方案数问题

    简述

    还是01背包,现在让你求取得物品总价值最大时的方案数。

    思路

    类似地,还是思考状态是什么以及如何从上一个状态转移过来。我们还设状态为前i个物品,以及背包体积v。动归数组存的是方案数,然后思考如何转移。

    我们设dp[i][j]存的是最大价值,f[i][j]存的是方案数。

    类比之前的方程,若dp[i][j]由dp[i-1][j]转移过来,那么f[i][j]的应该等于f[i-1][j];若dp[i][j]由dp[i][j-c[i]]转移过来,那么f[i][j]也应该等于f[i][j-c[i]];若dp[i][j-c[i]]与dp[i-1][j]相等,那么根据加法原理,f[i][j]应是f[i-1][j]与f[i][j-c[i]]的和。

    所以我们得出了方程:

    [f[i][j] = egin{cases} f[i-1][j] (dp[i-1][j] > dp[i][j-c[i]])\ f[i][j-c[i]] (dp[i-1][j] < dp[i][j-c[i])\ f[i-1][j] + f[i][j-c[i]] (dp[i-1][j] = dp[i][j-c[i]) end{cases} ]

    拓展:数字组合问题

    简述

    给你n块钱,有m种钱币,每种钱币只能用一次,问组成n块钱有多少种方法。

    思路

    既然你要考虑用dp做,那你肯定会毫无疑问地去选择前i个物品,选j个和钱数k作为状态,用背包来计算方案数。

    也就是

    [dp[i][j][k] += dp[i-1][j][k] ]

    [if(k >= v[i]) \ dp[i][j][k] += dp[i-1][j-1][k-v[i]] ]

    事实上这样会超时。

    所以要怎么做?

    先将物品排升序,枚举状态(i),表示第(i)个物品是未被选的物品中价值最小的一个物品。

    那么价值比它小的物品,都在它左面,而且都会被选,把他们用前缀和维护起来。

    现在你剩余一些钱j,从后面选取一些物品使价值最大但不超过j,这就是背包。

    所以一共二维,时间复杂度空间复杂度皆降低。

  • 相关阅读:
    Qt QApplication 类简介--Qt 类简介专题(四)
    回调函数
    C++类型转换总结
    Debug Error
    C++回调函数(callback)的使用
    Nokia5230连接电脑无线上网
    photoshop cs6\cs5找不到扫描仪的解决办法(Twain_32.8BA补丁下载)
    UML类图几种关系的总结
    实现单点登录
    poj 1151Atlantis线段树求矩形面积并解题报告
  • 原文地址:https://www.cnblogs.com/Ch-someone/p/9892201.html
Copyright © 2011-2022 走看看