动态规划DP之背包问题1---01背包问题

目录

问题描述:

问题应用场景:

如何解决01背包问题:

   朴素版(二维):

   优化(一维):

示例

二维: 

优化(一维):


问题描述:

        01背包问题通常描述为:有一个背包,它的容量为 V ,现在有 N 种不同的物品,编号为1...N ,其中每一种物品的重量为 w[i] ,价值为 v[i] 。问可以向这个背包中装入哪些物品,使得在不超过背包容量的前提下,背包中物品的总价值最大。

问题应用场景:

  1. 资源分配问题:在有限的资源下,如何分配资源才能使得收益最大化。比如,在限定的时间、成本和人力资源下,如何选择项目以获得最大的利润。

  2. 物流配送问题:在物流配送中,如何在有限的运输容量下,选择合适的货物组合,以最大化运输的价值或者利润。

  3. 金融投资问题:在投资中,如何选择不同的投资组合,使得投资组合的收益最大化。每个投资产品可以看作是一个物品,其收益和风险可以作为其价值和重量。

  4. 生产调度问题:在生产调度中,如何安排生产计划以最大化产出或者利润。每个生产计划可以看作是一个物品,其生产成本和产出价值可以作为其重量和价值。

如何解决01背包问题:

   朴素版(二维):

       使用 f[i][j] 来表示前 i 个物品,总体积是 j 的情况下,总价值最大是多少 。

  • 不选第 i 个物品,f[i][j] = f[i-1][j]
  • 选第  i 个物品,   f[i][j] = f[i-1][j-v_i]+w_i 

    则: f[i][j] =max(\ f[i-1][j],\ f[i-1][j-v_i]+w_i\ )

 

       时间复杂度  O(n^2)

 

   优化(一维):

        通过f[i][j] =max(\ f[i-1][j],\ f[i-1][j-v_i]+w_i\ ),可知,i 层的所有状态只与 i-1 层有关,所以没有必要把整个所有层都记下来。因此,可以把 层数的维度删掉,即 i 删掉。

        优化为 :f[j] =max(\ f[[j],\ f[j-v_i]+w_i\ )

 

示例

代码包含了二维和优化过后的(其中有一些细节要注意,代码中会提示):

有 N 件物品和一个容量是 V 的背包。每件物品只能使用一次。

第 i 件物品的体积是 vi,价值是 wi。

求解将哪些物品装入背包,可使这些物品的总体积不超过背包容量,且总价值最大。
输出最大价值。

输入格式

第一行两个整数,N,V,用空格隔开,分别表示物品数量和背包容积。

接下来有 N 行,每行两个整数 vi,wi,用空格隔开,分别表示第 i 件物品的体积和价值。

输出格式

输出一个整数,表示最大价值。

数据范围

0<N,V≤1000
0<vi,wi≤1000

输入样例

4 5
1 2
2 4
3 4
4 5

输出样例:

8

二维: 

import java.io.*;
import java.util.*;
 
class Main{
    static int N = 1010;
    static int n,V;
    static int[] v = new int[N]; // 体积
    static int[] w = new int[N]; // 价值
    static int[][] f = new int[N][N]; // 二维
    public static void main(String[] args) throws IOException{
        BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
        String[] s = in.readLine().split(" ");
        n = Integer.parseInt(s[0]);
        V = Integer.parseInt(s[1]);
        
        for(int i=1;i<=n;i++){
            s = in.readLine().split(" ");
            v[i] = Integer.parseInt(s[0]);
            w[i] = Integer.parseInt(s[1]);
        }
        
        // 01背包:
        for(int i=1;i<=n;i++){
            for(int j=0;j<=V;j++){
                f[i][j] = f[i-1][j];
                if(j>=v[i]) // 要确保j大于当前物品的体积才可以
                    f[i][j] = Math.max(f[i][j],f[i-1][j-v[i]]+w[i]); // 取最大价值
            }
        }
        System.out.println(f[n][V]); 
    }
}

优化(一维):

        因为当前是f[j] =max(\ f[[j],\ f[j-v_i]+w_i\ ) ,更新到第 i 层的 j 体积时,会覆盖前面0 到 j 的值,但是我们更新第 i 层 j 体积后面值 需要 i-1 层的值,因此,我们需要从 V 开始从后往前遍历更新;

import java.io.*;
import java.util.*;
 
class Main{
    static int N = 1010;
    static int n,V;
    static int[] v = new int[N]; // 体积
    static int[] w = new int[N]; // 价值
    static int[] f = new int[N]; // 二维
    public static void main(String[] args) throws IOException{
        BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
        String[] s = in.readLine().split(" ");
        n = Integer.parseInt(s[0]);
        V = Integer.parseInt(s[1]);
        
        for(int i=1;i<=n;i++){
            s = in.readLine().split(" ");
            v[i] = Integer.parseInt(s[0]);
            w[i] = Integer.parseInt(s[1]);
        }
        
        // 01背包优化:
        for(int i=1;i<=n;i++){
            for(int j=V;j>=v[i];j--){ // 从大到小遍历,大于v[i],因为体积不能小于当前物品的体积
                f[j] = Math.max(f[j],f[j-v[i]]+w[i]); // 取最大价值
            }
        }
        System.out.println(f[V]); 
    }
}
  • 22
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值