面试题之 【01背包问题】

62 篇文章 0 订阅
57 篇文章 1 订阅

1 题目

一个背包的总容量为V,现在有N类物品,第i类物品的重量为weight[i],价值为value[i]
那么往该背包里装东西,怎样装才能使得最终包内物品的总价值最大。

2 解题思路

本题目的解题思路类似金矿问题,放到背包里面的物体要么整个放进去,要么就不放。
那么根据动态规划的思路就有下一下两种情况:

  • 放进背包:
    此时将物体i放进背包,那么所剩物体减少1个,背包所能继续装物体的重量为V-weight[i],背包总价值加上物体i的价值。
  • 不放:
    此时不放到背包中,所剩物体减少1个,背包所能继续装物体的重量不变,背包的总价值维持不变。

这里假设函数f(n,w)是计算背包最大价值的函数,那么状态转移方程如下:

  • 放进背包:f(n,w)=max(f(n-1, w-weight[i]), f(n-1,w))
  • 不放进背包:f(n,w)=f(n-1,w)

那么具体的实现有以下三种:
(1)递归实现

	/**
     * 
     * @param n 物体的数量
     * @param w 背包所能放物体的最大重量
     * @param wt 每件物体的重量
     * @param val 每件物体的价值
     * @return
     */
    public int recursion(int n, int w, int[] wt, int[] val) {
        if (w == 0 || n == 0)
            return 0;
        if (wt[n - 1] < w) //放
            return Math.max(recursion(n - 1, w, wt, val), recursion(n - 1, w - wt[n - 1], wt, val) + val[n - 1]);
        else
            return recursion(n - 1, w, wt, val);
    }

(2)二维数组实现的动态规划

	/**
     *
     * @param n 物体的数量
     * @param w 背包所能放物体的最大重量
     * @param wt 每件物体的重量
     * @param val 每件物体的价值
     * @return
     */
    public int dpSolution(int n, int w, int[] wt, int[] val) {
        int[][] res = new int[n + 1][w + 1];
        for (int i = 1; i <= n; i++) {
            for (int j = 1; j <= w; j++) {
                if (j >= wt[i - 1])//背包所能承受的重量大于物体的重量,就放进去
                    res[i][j] = Math.max(res[i - 1][j], res[i - 1][j - wt[i - 1]] + val[i - 1]);
                else
                    res[i][j] = res[i -1][j];
            }
        }
        return res[n][w];
    }

(3)一维数组实现的动态规划

	/**
     *
     * @param n 物体的数量
     * @param w 背包所能放物体的最大重量
     * @param wt 每件物体的重量
     * @param val 每件物体的价值
     * @return
     */
    public int dpSolution2(int n, int w, int[] wt, int[] val){
        int [] dp=new int[w+1];
        for (int i = 1; i < n+1; i++) {
            for (int j=w;j>0;j--) {
                if (j>=wt[i-1])
                    dp[j] = Math.max(dp[j],dp[j-wt[i-1]]+val[i-1]);
            }
        }
        return dp[w];
    }

以上三种写法的算法复杂度可以参考金矿问题

3 总代码

package DP;

import java.util.Arrays;

/**
 * 背包问题:
 * 给你一个可装载重量为 W 的背包和 N 个物品,每个物品有重量和价值两个属性。
 * 其中第 i 个物品的重量为 wt[i],价值为 val[i],现在让你用这个背包装物品,
 * 最多能装的价值是多少?
 */
public class BackpagQuestion {
    /**
     *
     * @param n 物体的数量
     * @param w 背包所能放物体的最大重量
     * @param wt 每件物体的重量
     * @param val 每件物体的价值
     * @return
     */
    public int recursion(int n, int w, int[] wt, int[] val) {
        if (w == 0 || n == 0)
            return 0;
        if (wt[n - 1] < w) //放
            return Math.max(recursion(n - 1, w, wt, val), recursion(n - 1, w - wt[n - 1], wt, val) + val[n - 1]);
        else
            return recursion(n - 1, w, wt, val);
    }
    /**
     *
     * @param n 物体的数量
     * @param w 背包所能放物体的最大重量
     * @param wt 每件物体的重量
     * @param val 每件物体的价值
     * @return
     */
    public int dpSolution(int n, int w, int[] wt, int[] val) {
        int[][] res = new int[n + 1][w + 1];
        for (int i = 1; i <= n; i++) {
            for (int j = 1; j <= w; j++) {
                if (j >= wt[i - 1])//背包所能承受的重量大于物体的重量,就放进去
                    res[i][j] = Math.max(res[i - 1][j], res[i - 1][j - wt[i - 1]] + val[i - 1]);
                else
                    res[i][j] = res[i -1][j];
            }
        }
        return res[n][w];
    }
    /**
     *
     * @param n 物体的数量
     * @param w 背包所能放物体的最大重量
     * @param wt 每件物体的重量
     * @param val 每件物体的价值
     * @return
     */
    public int dpSolution2(int n, int w, int[] wt, int[] val){
        int [] dp=new int[w+1];
        for (int i = 1; i < n+1; i++) {
            for (int j=w;j>0;j--) {
                if (j>=wt[i-1])
                    dp[j] = Math.max(dp[j],dp[j-wt[i-1]]+val[i-1]);
            }
        }
        return dp[w];
    }


    public static void main(String[] args) {
        int n = 3;
        int w = 4;
        int[] wt = {2, 1, 3};
        int[] val = {4, 2, 3};
        BackpagQuestion backpagQuestion = new BackpagQuestion();
        int res = backpagQuestion.recursion(n, w, wt, val);
        System.out.println("递归求解:" + res);
        System.out.println("dp求解:" + backpagQuestion.dpSolution(n, w, wt, val));
        System.out.println("第二种解法:"+backpagQuestion.dpSolution2(n,w,wt,val));
    }
}

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值