01背包问题
package Chapter5;
import java.util.Scanner;
public class P002 {
static Scanner in = new Scanner(System.in);
static int N = 1010;
static int[] v = new int[N];
static int[] w = new int[N];
static int[][] f = new int[N][N];
static int n, m;
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
n = sc.nextInt(); //物品数量
m = sc.nextInt(); //背包容积
for (int i = 1; i <= n; i++)
{
v[i] = sc.nextInt();
w[i] = sc.nextInt();
}
//背包求解
//f[i][j] 表示前i件物品,体积j的 最大价值
for(int i=1;i<=n;i++){
for(int j=0;j<=m;j++){
//case1, 第i个物品不选
f[i][j] = f[i-1][j];
//如果背包的体积大于第i件物品
//case2,必选第i个物品 就是 f[i-1][j-v[i]]+w[i]
if(j>=v[i]){
f[i][j] = Math.max(f[i][j], f[i-1][j-v[i]]+w[i]);
}
}
}
System.out.println(f[n][m]);
}
}
完全背包问题
优化为2维
package Chapter5;
/**
*
* 完全背包问题
* @author vccyb
*
*/
import java.io.*;
import java.util.*;
public class P003 {
static final int N = 1010;
static int[] v = new int[N]; // 体积
static int[] w = new int[N]; // 价值
static int n; //物品数量
static int m; //背包容积
static int[][] f = new int[N][N];
public static void main(String[] args) throws IOException {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
String[] line = br.readLine().split(" ");
n = Integer.parseInt(line[0]); //物品数量
m = Integer.parseInt(line[1]); //背包体积
for (int i = 1; i <= n; i++) {
String[] line2 = br.readLine().split(" ");
v[i] = Integer.parseInt(line2[0]);
w[i] = Integer.parseInt(line2[1]);
}
//完全背包问题的解决 三维
//f[i][j] = f[i-1][j-k*v[i]]+k*w[i]
// for(int i=1;i<=n;i++){
// for(int j=0;j<=m;j++){
// for(int k = 0; k*v[i]<=j;k++){
// f[i][j] = Math.max(f[i][j], f[i-1][j-k*v[i]]+k*w[i]);
// System.out.println("前"+i+"个物品,体积小于"+j+"的最大收益为:"+f[i][j]);
// }
// }
// }
//完全背包的解决 二维
//f[i][j] = max(f[i-1][j],f[i][j-v[i]]+w[i])
for(int i=1;i<=n;i++){
for(int j=0;j<=m;j++){
//case1
f[i][j] = f[i-1][j];
//case2
if(j>=v[i]){
f[i][j] = Math.max(f[i][j], f[i][j-v[i]]+w[i]);
}
}
}
//输出结果
System.out.println(f[n][m]);
}
}
01背包和完全背包的小对比
多重背包问题朴素解法
多重背包问题:
物品多个,但不是无限个
k<s[i] 且 k*v[i]<j
package Chapter5;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
public class P004 {
static final int N = 110;
static int[] v = new int[N]; //物品体积
static int[] w = new int[N]; //物品价值
static int[] s = new int[N]; //物品数量
static int n; //物品种类数量
static int m; //背包的容积
static int[][] f = new int[N][N];
public static void main(String[] args) throws IOException {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
String[] line1 = br.readLine().split(" ");
n = Integer.parseInt(line1[0]);
m = Integer.parseInt(line1[1]);
for(int i=1;i<=n;i++){
String[] line2 = br.readLine().split(" ");
v[i] = Integer.parseInt(line2[0]);
w[i] = Integer.parseInt(line2[1]);
s[i] = Integer.parseInt(line2[2]);
}
//输入完毕
for(int i=1;i<=n;i++){
for(int j=0;j<=m;j++){
for(int k=0;k<=s[i]&&k*v[i]<=j;k++){
f[i][j] = Math.max(f[i][j], f[i-1][j-v[i]*k]+w[i]*k);
}
}
}
System.out.println(f[n][m]);
}
}
多重背包问题优化解法
考虑:怎么把多重背包问题化为01背包问题
v,w,s 拆分
v,w
v,w
…
v,w (重复s次)
就转化为了01背包问题
问题:拆法是很笨的 比如 每个物品有2000个,有2000种类物品。。。
时间复杂度也很高
二进制拆法
分组背包问题
package Chapter5;
import java.util.Scanner;
/**
* 分组背包问题
* @author vccyb
*
*/
public class P009 {
static final int N = 110;
static int[][] w = new int[N][N]; //物品价值
static int[][] v = new int[N][N]; //物品体积
static int[] s = new int[N]; //每一组的个数
static int[][] f = new int[N][N];
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
int n = sc.nextInt(); //物品组数
int m = sc.nextInt(); //背包容量
for(int i = 1;i <= n;i++)
{
s[i] = sc.nextInt();
for(int j = 1;j <= s[i];j++)
{
v[i][j] = sc.nextInt();
w[i][j] = sc.nextInt();
}
}
//分组背包求解
for(int i = 1;i <= n;i++)
for(int j = 0;j <= m;j ++)
{
f[i][j] = f[i - 1][j];//一个都不选时
for(int k = 1;k <= s[i];k++)//选第k个,k=0时v[i][k]为0
{
if(v[i][k] <= j)
f[i][j] = Math.max(f[i][j], f[i - 1][j - v[i][k]] + w[i][k]);
}
}
System.out.println(f[n][m]);
}
}