动态规划 之 零一背包

        动态规划中的零一背包问题是动规问题中十分典型且常见的一类问题,该类问题指的是:1.有一个容量为max_weight的背包和n个类型物品,每一种物品的质量为weight[i],价值为value[i](i为物品的编号),且每种类型的物品个数只有一个,问如何放置可以使得背包中的价值最大;2.可以转换为此类问题的问题。

一 典型问题

        假设有一个质量为5的背包和3个物品,且每个物品的质量都不一样,这组物品的质量和价值为weights=[1,2,3],values=[2,4,6]。问:如何放入物品可以使得背包中的总价值最大?

1.1 分析

        1.设置dp数组以及初始化:

        由于质量最大为5,因此设置dp数组的大小为5+1:vector dp(6, 0),假设目前以及遍历到第 i 号物品,则dp[j]表示,从0 - i 种物品中,可以让容量为j的背包得到的最大价值为dp[j]。

        初始化为0的原因是当还没有开始遍历物品(没有物品放入的时候,不同容量的背包价值也为0)。

        2.确定遍历顺序:

        先遍历物品,再遍历背包容量,然而对于背包容量的遍历,必须采取从容量为6的背包往前遍历,原因是如果采取从前往后遍历顺序的话,会导致质量为weight[i]的物品重复放入(从前往后是完全背包问题)。

        3.确定递推公式:dp[j] = max(dp[j], dp[j - weights[i]] + values[i])。

        该递推公式主要是当开始遍历第 i 号物品时,求dp[j](当遍历到 0 - i-1 号物品时,容量为j的背包的最大价值,不放入i号物品)与dp[j - weights[i]] + values[i](当遍历到 0 - i-1 号物品时,容量为 j - weights[i] 的背包的最大价值,放入i号物品)

1.2 代码

/*背包的容量为max_weight,物品质量为weights,物品价值为values*/
int DP_01bag(int max_weight, vector weights, vector values)
{
    vector dp(max_weight + 1, 0);
    for(int i = 0;i < weight.size();i++)
    {
        for(int j = max_weight;j >= weights[i];j--)
            dp[j] = max(dp[j], dp[j - weight[i]] + values[i]);
    }
    return dp[max_weight];
}

二 计算方法数问题

        计算方法数的问题又不同于之前的问题,之前的问题主要解决的问题是背包能否最大限度地填满(或者价值最大),这个问题是研究背包中填入这组物品的方法数。

2.1 分析

        问题: 假设有一个质量为5的背包和3个物品,且每个物品的质量都不一样,这组物品的质量和价值为weights=[1,2,3]。问:将背包填满的方法数?

        此类问题与之前那个问题的主要差别在于dp数组含义及初始化递推公式的不同:

        1.本题的dp数组含义为:dp[j]表示当遍历 0 - i 号物品时,容量为 j 的背包最多的填满方法。初始化方法是要在一开始将dp[0]初始化为1,其他初始化为0:因为当没开始遍历物品(不放入物品时),容量为0的背包填满的方法为1。

        2.本题的递推公式为:dp[j] = dp[j] + dp[j - weights[i]]。这个递推公式的含义是:当遍历到第 i 号物品时,容量为j的背包装满的方法数为:dp[j](当遍历到 i - 1 个物品时,容量为 j 的背包最多的填满方法,不放入第 i 号物品)和dp[j - weights[i]](当遍历到 i - 1个物品时,容量为 j - weights[i] 的背包放满的方法,放入第 i 号物品)之和。

2.2 代码

/*背包的容量为max_weight,物品质量为weights*/
int DP_01bag(int max_weight, vector weights)
{
    vector dp(max_weight + 1, 0);
    dp[0] = 1;
    for(int i = 0;i < weight.size();i++)
    {
        for(int j = max_weight;j >= weights[i];j--)
            dp[j] = dp[j] + dp[j - weight[i]];
    }
    return dp[max_weight];
}

三 总结

        动规问题解决步骤:

        1.确定dp数组含义;

        2.确定递推公式;

        3.根据递推公式确定dp数组该如何初始化;

        4.确定循环遍历顺序。

你可能感兴趣的:(动态规划,算法)