动态规划——01背包问题

题目

假设有一个背包,它可以装重量为8的物品,给出4个物品,问,如何装才能使得这个背包装的物品的总价值最大?背包到底装入了哪些物品?

思路

利用动态规划来做,我们,要开一个dp数组,数组的行数与物品的个数+1相等,数组的列数与背包的能装的最大价值+1相等。
在搜索的时候,行数表示物品的编号,列数表示当前背包的体积。

我们只需要首先考虑,该物品能不能够放进去背包,那么就是当前背包的能装的体积要大于当前要考虑的物品的体积【注意:这里是拿一个空的背包去装,与前面是否装进去物品没有关系】,假设不能够装进去当前物品,那么,当前的值等于在同等背包体积的情况下n-1个物品的所能装入的最大价值。即

dp[i][j]=dp[i-1][j];

假设能够装进去该物品,那么就要考虑装不装该物品,假设不装,那么值就是在同等体积的背包下前n-1个物品的最大价值,如果能够装进去,那么,当前位置的最大价值就是给当前物品预留了体积之后,在剩余价值里,对于前n-1个物品而言,所能取得的最大家价值之和。
在这里插入图片描述

在以上的值中取出一个大的即可。

完整的动态规划代码:

dp[i][j]=Math.max(dp[i-1][j],dp[i-1][j-weight[i]]+value[i]);
  public static  void work(){
        for (int i=1;i<5;++i)
        {
            for (int j=1;j<9;++j)
            {
                //判断,即拿一个当前体积的空背包,判断当前物品是否能够放进去背包
                if (weight[i]>j) //不能放进去
                {
                    //在当前背包体积的情况下,前面n-1个物品的最大和组合就是当前n个物品的最大和组合
                    dp[i][j]=dp[i-1][j];
                }
                else //当前物品可以装入背包,但不一定要放进去
                {
                    //可以放,但不放,取前面情况;可以放,也放,要先预留出对应的位置,
                    //取出n-1个物品在当前预留完位置之后的最大价值组合并且加上当前物品的组合
                    //再去取最大值
                    dp[i][j]=Math.max(dp[i-1][j],dp[i-1][j-weight[i]]+value[i]);
                }
            }
        }
}

该背包到底装了哪些物品呢?

我们需要从答案的位置进行回溯,假设在背包体积相同的情况下,n个物品所能取得的最大价值与n-1个物品的最大价值一致,那么就表示当前物品没有放到背包中。这个时候,就需要回溯n-1个物品的对应的体积的情况,

假设在同等体积的背包情况下,当前n个物品所取得的最大价值与前n-1个物品所取得的最大价值不一致【即当前物品是在预留了足够的体积后所取得的当前物品的价值与剩下n-1个物品在剩下的体积重所取得的最大价值之和】,那么就表示该物品进入到了背包之中。

 //回溯到底装了哪些物品
    public static  void find(int i,int j)
    {
        if (i==0) //当搜寻到第0行的时候,结束回溯
        {
            for (int g=0;g<5;++g)
            {
                System.out.print(object[g]+" ");
            }
            return;
        }
        if (dp[i][j]==dp[i-1][j])
        {
            object[i]=0;//即在背包体积固定的情况下,对于前n个物品和前n-1个物品,
                        // 背包的最大价值没有变化,即该物品没有放入背包
            find(i-1,j);
        }
        //当前物品被装入时,对应位置的最大价值得到验证
        else if (dp[i][j]==dp[i-1][j-weight[i]]+value[i])
        {
            object[i]=1;
            find(i-1,j-weight[i]);//找寻去除掉当前的物品的价值剩余价值并且对应的n-1个物品的最大价值组合
        }
    }

在这里插入图片描述


整道题的代码:

//背包的最大价值为8
public class Main {
    static int weight[]={0,2,3,4,5};//重量数组
    static int value[]={0,3,4,5,6};//价值数组

    //行数与物品的个数有关,列数与背包的最大容量有关
    static int dp[][]=new int[5][9];

    static int object[]=new int[5];//结果数组

    public static void main(String[] args) {
        work();

    }

    public static  void work(){
        for (int i=1;i<5;++i)
        {
            for (int j=1;j<9;++j)
            {
                //判断,即拿一个当前体积的空背包,判断当前物品是否能够放进去背包
                if (weight[i]>j) //不能放进去
                {
                    //在当前背包体积的情况下,前面n-1个物品的最大和组合就是当前n个物品的最大和组合
                    dp[i][j]=dp[i-1][j];
                }
                else //当前物品可以装入背包,但不一定要放进去
                {
                    //可以放,但不放,取前面情况;可以放,也放,要先预留出对应的位置,
                    //取出n-1个物品在当前预留完位置之后的最大价值组合并且加上当前物品的组合
                    //再去取最大值
                    dp[i][j]=Math.max(dp[i-1][j],dp[i-1][j-weight[i]]+value[i]);
                }
            }
        }
        //行数减1.列数减1
        System.out.println(dp[4][8]);
        find(4,8);
    }

    //回溯到底装了哪些物品
    public static  void find(int i,int j)
    {
        if (i==0) //当搜寻到第0行的时候,结束回溯
        {
            for (int g=0;g<5;++g)
            {
                System.out.print(object[g]+" ");
            }
            return;
        }
        if (dp[i][j]==dp[i-1][j])
        {
            object[i]=0;//即在背包体积固定的情况下,对于前n个物品和前n-1个物品,
                        // 背包的最大价值没有变化,即该物品没有放入背包
            find(i-1,j);
        }
        //当前物品被装入时,对应位置的最大价值得到验证
        else if (dp[i][j]==dp[i-1][j-weight[i]]+value[i])
        {
            object[i]=1;
            find(i-1,j-weight[i]);//找寻去除掉当前的物品的价值剩余价值并且对应的n-1个物品的最大价值组合
        }
    }
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值