目录
问题描述:
01背包问题通常描述为:有一个背包,它的容量为 ,现在有
种不同的物品,编号为
,其中每一种物品的重量为
,价值为
。问可以向这个背包中装入哪些物品,使得在不超过背包容量的前提下,背包中物品的总价值最大。
问题应用场景:
-
资源分配问题:在有限的资源下,如何分配资源才能使得收益最大化。比如,在限定的时间、成本和人力资源下,如何选择项目以获得最大的利润。
-
物流配送问题:在物流配送中,如何在有限的运输容量下,选择合适的货物组合,以最大化运输的价值或者利润。
-
金融投资问题:在投资中,如何选择不同的投资组合,使得投资组合的收益最大化。每个投资产品可以看作是一个物品,其收益和风险可以作为其价值和重量。
-
生产调度问题:在生产调度中,如何安排生产计划以最大化产出或者利润。每个生产计划可以看作是一个物品,其生产成本和产出价值可以作为其重量和价值。
如何解决01背包问题:
朴素版(二维):
使用 来表示前
个物品,总体积是
的情况下,总价值最大是多少 。
- 不选第
个物品,
- 选第
个物品,
则:
时间复杂度 O(n^2)
优化(一维):
通过,可知,
层的所有状态只与
层有关,所以没有必要把整个所有层都记下来。因此,可以把 层数的维度删掉,即
删掉。
优化为 :
示例
代码包含了二维和优化过后的(其中有一些细节要注意,代码中会提示):
有 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]);
}
}
优化(一维):
因为当前是 ,更新到第
层的
体积时,会覆盖前面
到
的值,但是我们更新第
层
体积后面值 需要
层的值,因此,我们需要从
开始从后往前遍历更新;
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]);
}
}