0/1背包问题的动态规划分析

0/1背包问题: 
简单来说就是,面对体积和价值不同的物品,如果在背包容量下尽可能装价值最多的物品。而且每个物品只有一件,当物品数较多,价值量区别不是那么明显时,这对一个贪财老可是一个巨大的折磨(哈哈),我们如何去解决这样一个问题呢! 
假设有一个容量为10的背包 
另外有五个供选择的物品编号为:1 2 3 4 5 
    物品的重量(w)分别为:2 2 6 5 4 
    物品的价值(p)分别为:6 3 5 4 6 

问:你会选择装那几个物品呢? 

      对于这个问题可能试几下能够试出来,但当物品数量较多,情况会十分复杂,无法用试的心态下手。有些人可能想穷举出每一种情况找出最大的情况。但是,这里的穷举是一件非常繁重的任务,而且这里的穷举不能利用计算机完成。。任何想使用计算机来处理的事情,必须告诉计算机这个速度惊人的傻瓜一个固定的套路。。面对这种情况,我们需要动态规划的思想来分析这个问题。

动态规划分析:

介绍之前我们定义f(i,w)表示可选物品为i个,背包容量为w时的最佳解。

因此该问题就可以表示为求f(5,10)的值

如果只先针对物品5,该问题可以分为两种情况,即装了物品5和没装物品5

因此该问题可以转化为求这两种情况的最大值:

如果没装物品5:即求f(4,10)

如果装了物品5:即求f(4,6)+ 6

至此问题解决了吗,我觉得解决了,如果单单作为一个上层决策者,他的任务完成了,他只需要吩咐两个下属分别求这样两个问题,

问题1:给出一个容量为10的背包去装编号为1 2 3 4这四个物品并求出最大价值解。

问题2:给出一个容量为6的背包去装编号为1 2 3 4 这四个物品并求出最大价值解。

至于下属怎么做,上层决策者不关心,决策者只需根据两个下属给出的结果来挑选一个最大值即可,当然下属也能用同样的方法去分配自己的下属解决自己决策出的子问题。

如果能看出下面给出的动态规划的分配步骤,就表明真的对动态规划理解了。



说了这么多通俗的话,来点教科书上的一个动态分析的状态方程,相信现在看这个方程应该很容易理解了
f(i,w)=max{f(i-1,w), f(i-1, w-wi)+pi} wi为敌i个物品的重量,pi为第i个物品的价值
另外还应满足当w<wi时,f(i,w)=f(i-1,w)(即背包的容量不足以装下第i个物品

如何将该动态分析用代码来实现呢?

代码实现时,我们从背包容量为1,以及是否装物品1开始向上递推,且f[i][0]=0h和f[0][j]=0,核心代码即为背包问题的状态方程,此处注意最大价值数组f[i][j]从下标1开始循环,而重量w和价值p数组下标为从下标0开始,因此w p数组中下标应减去1

#include<iostream>
using namespace std;
int package(int w[],int p[],int n,int c)
{
    int i,j;
    int f[n+1][c+1];//当背包容量为c,物品为n个时可装的最大价值
    for(i=0;i<n+1;++i)
        f[i][0]=0;
    for(j=0;j<c+1;++j)
        f[0][j]=0;
    for(i=1;i<n+1;++i)//i表示装第i个物品时的情况
    {
        for(j=1;j<c+1;++j)//装第i个物品时,背包剩余的容量为j
        {
            if(w[i-1]>j)
                f[i][j]=f[i-1][j];
            else
                f[i][j]=max(f[i-1][j],f[i-1][j-w[i-1]]+p[i-1]);//物品从下标0开始,而i=0或j=0的场合也需要
        }
    }
    return f[i-1][j-1];
}

int main()
{
    int w[5]={2,2,6,5,4};
    int p[5]={6,3,5,4,6};
    int c=10;
    cout << package(w,p,5,c) << endl;
}
输出结果为:15



猜你喜欢

转载自blog.csdn.net/Gouhailiang/article/details/53204947