AcWing 11. Java-背包问题求方案数
原题链接
中等
作者:
熊本熊本熊
,
2019-05-02 15:48:47
,
所有人可见
,
阅读 1841
import java.util.Scanner;
import java.util.Arrays;
public class Main{
public static void main(String[] args) {
// N个物品
int N;
// 背包体积
int V;
// 每个物品的体积
int[] v;
// 每一个物品的价值
int[] w;
// start input
Scanner input = new Scanner(System.in);
N = input.nextInt();
V = input.nextInt();
v = new int[N + 1];
w = new int[N + 1];
for (int i = 1; i <= N; i++) {
v[i] = input.nextInt();
w[i] = input.nextInt();
}
input.close();
// start solution
Main solution = new Main();
System.out.println(solution.solution_count_2(N,V,v,w));
}
public int solution_count_1(int N, int V, int[]v, int[]w){
int[][] dp = new int[N+1][V+1];
int[][] count = new int[N+1][V+1];
// 没有物品可以选择时,什么都不选,也是一种方案
Arrays.fill(count[0],1);
final int MOD = 1000000007;
for(int i = 1; i <= N; i++){
for(int j = 0; j <= V; j++){
if(j >= v[i]){
if(dp[i-1][j] < dp[i-1][j-v[i]] + w[i]){
// 选择当前物品的收益更高
// 更新当前收益
dp[i][j] = dp[i-1][j-v[i]] + w[i];
// 当前方案只是在之前方案的基础上加了当前的物品,因此方案数量不变
count[i][j] = count[i-1][j-v[i]];
}else if(dp[i-1][j] == dp[i-1][j-v[i]] + w[i]){
// 两种办法收益相等
// 更新当前收益
dp[i][j] = dp[i-1][j];
// 当前方案有两种选择,一是不增加当前物品,二是增加当前物品,所以方案数量等于二者之和
count[i][j] = count[i-1][j] + count[i-1][j-v[i]];
count[i][j] %= MOD;
}else {
// 选择当前物品的收益更高
// 更新当前收益
dp[i][j] = dp[i-1][j];
// 当前方案不增加物品,与之前的方案等同
count[i][j] = count[i-1][j];
count[i][j] %= MOD;
}
}else {
// 由于客观条件限制,无法选择当前物品
// 更新当前收益
dp[i][j] = dp[i-1][j];
// 当前方案不增加物品,与之前的方案等同
count[i][j] = count[i-1][j];
count[i][j] %= MOD;
}
}
}
return count[N][V];
}
public int solution_count_2(int N, int V, int[]v, int[]w){
int[] dp = new int[V+1];
// 当背包体积为1~V的时候,最佳方案的总数
int[] count = new int[V+1];
// 初始化,此时的count代表i=0,即没有物品可以选择时
// 什么都不选,也是一种方案
Arrays.fill(count,1);
final int MOD = 1000000007;
for(int i = 1; i <= N; i++){
for(int j = V; j >= v[i]; j--){
if(dp[j] < dp[j-v[i]] + w[i]){
// 选择当前物品的收益要高,因此这里dp的选择必然是选择当前物品,
// 因为是必然,所以这样的方案数量不变
count[j] = count[j-v[i]];
count[j] %= MOD;
}else if(dp[j] == dp[j-v[i]] + w[i]){
// 二者的收益相等,这里可以选,也可以不选
// 因此这里是加上count[j-v[i]]
count[j] += count[j-v[i]];
count[j] %= MOD;
}else {
// 不选的收益更高,那么这里dp的选择必然是不选
// 因此保持count[n-1][j]即可
}
dp[j] = Math.max(dp[j],dp[j-v[i]] + w[i]);
}
}
return count[V];
}
}