AcWing-2.01背包问题
题目描述
有 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
思路+优化(利用滚动数组降维,输入优化)
状 态 表 示 : f ( i , j ) , 表 示 从 1 到 i 中 选 容 量 不 超 过 j 的 所 有 价 值 集 合 状态表示:f(i,j),表示从1到i中选容量不超过j的所有价值集合 状态表示:f(i,j),表示从1到i中选容量不超过j的所有价值集合
属 性 : M a x 属性:Max 属性:Max
核 心 : 最 后 一 个 i 取 或 者 不 取 核心:最后一个i取或者不取 核心:最后一个i取或者不取
状 态 划 分 : f ( i − 1 , j ) 取 0 个 i 或 1 个 i 状态划分:f(i-1,j)取0个i或1个i 状态划分:f(i−1,j)取0个i或1个i
由状态划分可得到状态转移方程:
f ( i , j ) = M a x ( f ( i − 1 , j ) , f ( i − 1 , j − v i ) + w i ) f(i,j) = Max(f(i-1,j),f(i-1,j-vi)+wi) f(i,j)=Max(f(i−1,j),f(i−1,j−vi)+wi)
用状态方程可知,需要利用的仅有当前行和上一行所以可以利用滚动数组的概念将二维降至一维,即:
f ( j ) = M a x ( f ( j ) , f ( j − v i ) + w i ) f(j) = Max(f(j),f(j-vi)+wi) f(j)=Max(f(j),f(j−vi)+wi)
注意:因为每个物品i只能取一个,而且用的是一维数组,所以j只能从后往前循环以确保物品i是第一次被取,即数组前面的值没有受到物品i的影响
因为物品是按读入的顺序处理的,所以还可以边读边处理。
综上所述:
核心代码
for(int i=1;i<=n;i++) {
int x = r.nextInt(),y = r.nextInt();
for(int j=v;j>=x;j--) {
dp[j] = Math.max(dp[j], dp[j-x]+y);
}
}
完整代码
package acWing002;
public class Main2 {
static int N = 1010;
static int n,v;
static int dp[] = new int[N];
public static void main(String[] args) throws Exception{
Read r = new Read();
n = r.nextInt();v = r.nextInt();
for(int i=1;i<=n;i++) {
int x = r.nextInt(),y = r.nextInt();
for(int j=v;j>=x;j--) {
dp[j] = Math.max(dp[j], dp[j-x]+y);
}
}
System.out.println(dp[v]);
}
}
class Read{
StreamTokenizer st = new StreamTokenizer(new BufferedReader(new InputStreamReader(System.in)));
public int nextInt() throws Exception{
st.nextToken();
return (int)st.nval;
}
}