有 N 件物品和一个容量是 V 的背包。每件物品只能使用一次。
第 i 件物品的体积是 vi,价值是 wi。
求解将哪些物品装入背包,可使这些物品的总体积不超过背包容量,且总价值最大。
输出最大价值。
输入格式
第一行两个整数,N,V,用空格隔开,分别表示物品数量和背包容积。
接下来有 N 行,每行两个整数 vi,wi,用空格隔开,分别表示第 i 件物品的体积和价值。
输出格式
输出一个整数,表示最大价值。
数据范围
0
4 5
1 2
2 4
3 4
4 5
输出样例:
8
二维数组,
优化:变为一维
import java.util.*;
public class beibao01{
public static void main(String[] args){
Scanner sc = new Scanner(System.in);
int n = sc.nextInt();
int v = sc.nextInt();
int[] v1 = new int[n+1];
int[] w = new int[n+1];
for(int i = 1; i<=n; i++){
v1[i] = sc.nextInt();
w[i] = sc.nextInt();
}
// int res = helper(v1,w,n,v);
int res1 = helper1(v1,w,n,v);
System.out.println(res1);
}
private static int helper1(int[] v1, int[] w, int n, int v) {
int res = 0;
int[] dp = new int[v+1];
for(int i=1;i<=n;i++){
for(int j = v;j>=v1[i];j--){
dp[j] = Math.max(dp[j],dp[j-v1[i]]+w[i]);
}
}
return dp[v];
}
public static int helper(int[] v1,int[] w, int n ,int v){
int res = 0;
int[][] dp = new int[n+1][v+1];
for(int i=1;i<=n;i++){
for(int j = 1;j<=v;j++){
dp[i][j] = dp[i-1][j];
if(j>=v1[i]){
dp[i][j] = Math.max(dp[i][j],dp[i-1][j-v1[i]]+w[i]);
}
}
}
return dp[n][v];
}
}
因为
dp[i][j] = Math.max(dp[i][j],dp[i-1][j-v1[i]]+w[i]);中dp[i-1][j-v1[i]]取得是i-1的对应的,如果正序,那变为一维则成了dp【i】[j-v1[i]],不是i-1,如何保证是没算过的,就倒叙。j-v1[i] <=j.
因为求得是小于等于v的最大价值,初始化所有都是0.
如果要是只求恰巧等于v的最大价值,初始化时,0的位置是0,其他位置都变为负无穷。这样可以确保所有状态都是从f【0】转移过来。
有 N 种物品和一个容量是 V 的背包,每种物品都有无限件可用。
第 i 种物品的体积是 vi,价值是 wi。
求解将哪些物品装入背包,可使这些物品的总体积不超过背包容量,且总价值最大。
输出最大价值。
输入格式
第一行两个整数,N,V,用空格隔开,分别表示物品种数和背包容积。
接下来有 N 行,每行两个整数 vi,wi,用空格隔开,分别表示第 i 种物品的体积和价值。
输出格式
输出一个整数,表示最大价值。
数据范围
0
4 5
1 2
2 4
3 4
4 5
输出样例:
10
两个代码其实只有一句不同(注意下标)
f[i][j] = max(f[i][j],f[i-1][j-v[i]]+w[i]);//01背包
f[i][j] = max(f[i][j],f[i][j-v[i]]+w[i]);//完全背包问题
因为和01背包代码很相像,我们很容易想到进一步优化。核心代码可以改成下面这样
for(int i = 1 ; i<=n ;i++)
for(int j = v[i] ; j<=m ;j++)//注意了,这里的j是从小到大枚举,和01背包不一样
{
f[j] = max(f[j],f[j-v[i]]+w[i]);
}
import java.util.*;
public class beibaowanquan{
public static void main(String[] args){
Scanner sc = new Scanner(System.in);
int n = sc.nextInt();
int v = sc.nextInt();
int[] v1 = new int[n+1];
int[] w = new int[n+1];
for(int i = 1; i<=n; i++){
v1[i] = sc.nextInt();
w[i] = sc.nextInt();
}
// int res = helper(v1,w,n,v);
int res1 = helper1(v1,w,n,v);
System.out.println(res1);
}
private static int helper1(int[] v1, int[] w, int n, int v) {
int[] dp = new int[v+1];
for(int i=1;i<=n;i++){
for(int j = v1[i];j<=v;j++){
dp[j] = Math.max(dp[j],dp[j-v1[i]]+w[i]);
}
}
return dp[v];
}
public static int helper(int[] v1,int[] w, int n ,int v){
int res = 0;
int[][] dp = new int[n+1][v+1];
for(int i=1;i<=n;i++){
for(int j = 1;j<=v;j++){
dp[i][j] = dp[i-1][j];
if(j>=v1[i]){
dp[i][j] = Math.max(dp[i][j],dp[i-1][j-v1[i]]+w[i]);
}
}
}
return dp[n][v];
}
}
有 N 种物品和一个容量是 V 的背包。
第 i 种物品最多有 si 件,每件体积是 vi,价值是 wi。
求解将哪些物品装入背包,可使物品体积总和不超过背包容量,且价值总和最大。
输出最大价值。
输入格式
第一行两个整数,N,V,用空格隔开,分别表示物品种数和背包容积。
接下来有 N 行,每行三个整数 vi,wi,si,用空格隔开,分别表示第 i 种物品的体积、价值和数量。
输出格式
输出一个整数,表示最大价值。
数据范围
0
4 5
1 2 3
2 4 1
3 4 3
4 5 2
输出样例:
10
改进完全背包
import java.util.*;
public class duochong1 {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
int n = sc.nextInt();
int v = sc.nextInt();
int[] v1 = new int[n + 1];
int[] w = new int[n + 1];
int[] s = new int[n + 1];
for (int i = 1; i <= n; i++) {
v1[i] = sc.nextInt();
w[i] = sc.nextInt();
s[i] = sc.nextInt();
}
int res1 = helper1(v1, w, n, v, s);
System.out.println(res1);
}
private static int helper1(int[] v1, int[] w, int n, int v, int[] s) {
int[] dp = new int[v + 1];
for (int i = 1; i <= n; i++) {
for (int j = v; j >= v1[i]; j--) {
for (int k = 0; k <= s[i] && k * v1[i] <= j; k++) {
dp[j] = Math.max(dp[j], dp[j - k * v1[i]] + k * w[i]);
}
}
}
return dp[v];
}
}
有 N 种物品和一个容量是 V 的背包。
第 i 种物品最多有 si 件,每件体积是 vi,价值是 wi。
求解将哪些物品装入背包,可使物品体积总和不超过背包容量,且价值总和最大。
输出最大价值。
输入格式
第一行两个整数,N,V,用空格隔开,分别表示物品种数和背包容积。
接下来有 N 行,每行三个整数 vi,wi,si,用空格隔开,分别表示第 i 种物品的体积、价值和数量。
输出格式
输出一个整数,表示最大价值。
数据范围
0
本题考查多重背包的二进制优化方法。
输入样例
4 5
1 2 3
2 4 1
3 4 3
4 5 2
输出样例:
10
将多重背包拆成01背包,但不是一个一个拆,使用二进制拆
大神解法:
import java.util.*;
public class Main{
void run(){
int n = jin.nextInt();
int m = jin.nextInt();
int p = 1;
for (int i = 1; i <= n ; i++){
int V = jin.nextInt();
int W = jin.nextInt();
int S = jin.nextInt();
int k = 1;
while (S > k){
v[p] = V*k;
w[p] = W*k;
S -= k;
k *= 2;
p++;
}
if (S > 0){
v[p] = V*S;
w[p] = W*S;
p ++;
}
}
int res = dp(p, m);
System.out.println(res);
}
自己写的,未通过:
import java.util.*;
public class beibao02 {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
int n = sc.nextInt();
int v = sc.nextInt();
int maxN = 200002;
int[] v1 = new int[maxN];
int[] w = new int[maxN];
int p = 1;
for (int i = 1; i <= n; i++) {
int vv = sc.nextInt();
int ww = sc.nextInt();
int s = sc.nextInt();
int k = 1;
while (s > k) {
v1[p] = vv * k;
w[p] = ww * k;
s -= k;
k *= 2;
p++;
}
if (s > 0) {
v1[p] = vv * s;
w[p] = ww * s;
p++;
}
}
int res1 = helper1(v1, w, n, v);
System.out.println(res1);
}
private static int helper1(int[] v1, int[] w, int n, int v) {
int[] dp = new int[v + 1];
for (int i = 1; i <= n; i++) {
for (int j = v; j >= v1[i]; j--) {
dp[j] = Math.max(dp[j], dp[j - v1[i]] + w[i]);
}
}
return dp[v];
}
}
有 N 种物品和一个容量是 V 的背包。
第 i 种物品最多有 si 件,每件体积是 vi,价值是 wi。
求解将哪些物品装入背包,可使物品体积总和不超过背包容量,且价值总和最大。
输出最大价值。
输入格式 接下来有 N 行,每行三个整数 vi,wi,si,用空格隔开,分别表示第 i 种物品的体积、价值和数量。 输出格式 数据范围 输入样例 有 N 种物品和一个容量是 V 的背包。 物品一共有三类: 第一类物品只能用1次(01背包); 求解将哪些物品装入背包,可使物品体积总和不超过背包容量,且价值总和最大。 输入格式 接下来有 N 行,每行三个整数 vi,wi,si,用空格隔开,分别表示第 i 种物品的体积、价值和数量。 si=−1 表示第 i 种物品只能用1次; 数据范围 作者:FUZZ 有 N 件物品和一个容量是 V 的背包,背包能承受的最大重量是 M。 每件物品只能用一次。体积是 vi,重量是 mi,价值是 wi。 求解将哪些物品装入背包,可使物品总体积不超过背包容量,总重量不超过背包可承受的最大重量,且价值总和最大。 输入格式 接下来有 N 行,每行三个整数 vi,mi,wi,用空格隔开,分别表示第 i 件物品的体积、重量和价值。 输出格式 数据范围 作者:熊本熊本熊 有 N 组物品和一个容量是 V 的背包。 每组物品有若干个,同一组内的物品最多只能选一个。 求解将哪些物品装入背包,可使物品总体积不超过背包容量,且总价值最大。 输出最大价值。 输入格式 接下来有 N 组数据: 每组数据第一行有一个整数 Si,表示第 i 个物品组的物品数量; 数据范围
第一行两个整数,N,V (0
输出一个整数,表示最大价值。
0
提示
本题考查多重背包的单调队列优化方法。
4 5
1 2 3
2 4 1
3 4 3
4 5 2
输出样例:
10混合背包问题
第二类物品可以用无限次(完全背包);
第三类物品最多只能用 si 次(多重背包);
每种体积是 vi,价值是 wi。
输出最大价值。
第一行两个整数,N,V,用空格隔开,分别表示物品种数和背包容积。
si=0 表示第 i 种物品可以用无限次;
si>0 表示第 i 种物品可以使用 si 次;
输出格式
输出一个整数,表示最大价值。
0
输入样例
4 5
1 2 -1
2 4 1
3 4 0
4 5 2
输出样例:
8solution
import java.util.Scanner;
public class Main{
public static void main(String[] args){
Scanner sc = new Scanner(System.in);
int N = sc.nextInt(); // 物品个数
int V = sc.nextInt(); // 背包总容量
int[] dp = new int[V + 1];
for(int i = 0; i < N; i++){
int v = sc.nextInt(); // 体积
int w = sc.nextInt(); // 价值
int s = sc.nextInt(); // 数量
if(s == 0){
// 完全背包问题
for(int j = v; j <= V; j++){
dp[j] = Math.max(dp[j], dp[j - v] + w);
}
}else{
// 多重背包问题,01背包是多重背包的特例,可以一并处理
s = Math.abs(s);
for(int j = 1; s >= j; s -= j, j *= 2){
for(int k = V; k >= j * v; k--){
dp[k] = Math.max(dp[k], dp[k - j * v] + j * w);
}
}
if(s > 0){
for(int j = V; j >= s * v; j--){
dp[j] = Math.max(dp[j], dp[j - s * v] + s * w);
}
}
}
}
System.out.println(dp[V]);
}
}
链接:https://www.acwing.com/solution/content/4116/二维费用背包问题
输出最大价值。
第一行两个整数,N,V,M,用空格隔开,分别表示物品件数、背包容积和背包可承受的最大重量。
输出一个整数,表示最大价值。
0
4 5 6
1 2 3
2 4 4
3 4 5
4 5 6
输出样例:
8import java.util.Scanner;
public class Main{
public static void main(String[] args) {
// N个物品
int N;
// 背包体积
int V;
// 背包承受最大的重量
int M;
// 每个物品的体积
int[] v;
// 每一个物品的重量
int[] m;
// 每一个物品的价值
int[] w;
// start input
Scanner input = new Scanner(System.in);
N = input.nextInt();
V = input.nextInt();
M = input.nextInt();
v = new int[N + 1];
m = new int[N + 1];
w = new int[N + 1];
for (int i = 1; i <= N; i++) {
v[i] = input.nextInt();
m[i] = input.nextInt();
w[i] = input.nextInt();
}
input.close();
Main solution = new Main();
// System.out.println(solution.two_dimension_knapsack_problem_1(N,V,M,v,m,w));
System.out.println(solution.two_dimension_knapsack_problem_2(N,V,M,v,m,w));
}
/**
* 传统解法,即没有优化的解法,这个解法对于n种约束需要构建一个n维的dp矩阵
* @param N 题目提供N个物品
* @param V 背包的总体积
* @param M 背包承受最大的重量
* @param v 每个物品的体积 v[i],长度为N+1,第0位无用
* @param m 每个物品的重量 m[i],长度为N+1,第0位无用
* @param w 每个物品的价值 w[i],长度为N+1,第0位无用
* @return 在给定物品,背包总体积以及背包最大重量的情况下,背包能装的物品的最高总价值
*/
public int two_dimension_knapsack_problem_1(int N, int V, int M, int[] v, int[] m, int[] w){
int[][][] dp = new int[N+1][V+1][M+1];
for(int i = 1; i <= N; i++){
for(int j = 1; j <= V; j++){
for(int k = 1; k <= M; k++){
if(j < v[i] || k < m[i]){
// 客观条件限制,不能选择当前物品N
dp[i][j][k] = dp[i-1][j][k];
}else {
dp[i][j][k] = Math.max(dp[i-1][j][k], dp[i-1][j-v[i]][k-m[i]] + w[i]);
}
}
}
}
return dp[N][V][M];
}
/**
* 优化版
* @param N 题目提供N个物品
* @param V 背包的总体积
* @param M 背包承受最大的重量
* @param v 每个物品的体积 v[i],长度为N+1,第0位无用
* @param m 每个物品的重量 m[i],长度为N+1,第0位无用
* @param w 每个物品的价值 w[i],长度为N+1,第0位无用
* @return 在给定物品,背包总体积以及背包最大重量的情况下,背包能装的物品的最高总价值
*/
public int two_dimension_knapsack_problem_2(int N, int V, int M, int[] v, int[] m, int[] w) {
int[][] dp = new int[V+1][M+1];
for(int i = 1; i <= N; i++){
for(int j = V; j >= 1; j--){
for(int k = M; k>= 1; k--){
if(j < v[i] || k < m[i]){
// 客观条件限制,不能选择当前物品N
dp[j][k] = dp[j][k];
}else {
dp[j][k] = Math.max(dp[j][k], dp[j-v[i]][k-m[i]] + w[i]);
}
}
}
}
return dp[V][M];
}
/**
* 所谓的优化,就是省去了代表N的那一维,即将:
* dp[i][j][k] = Math.max(dp[i-1][j][k], dp[i-1][j-v[i]][k-m[i]] + w[i]);
* 优化为
* dp[j][k] = Math.max(dp[j][k], dp[j-v[i]][k-m[i]] + w[i]);
* 这样整体的空间复杂度可以除以N,空间复杂度降低了;时间复杂度不变,还是三层循环
*
* 优化需要对遍历的顺序做一点改变,以保证遍历的时候,拿到的数据是 真·[i-1] 时刻的,而不是被更新过了的
* 如果不修改遍历的顺序,更新矩阵数据的时候时,对于体积V和质量M ,是按照从小到大的顺序更新的,
* 即,在计算dp[j][k] = Math.max(dp[j][k], dp[j-v[i]][k-m[i]] + w[i]) 时,
* 本来要求dp[i][j][k] = Math.max(dp[i-1][j][k], dp[i-1][j-v[i]][k-m[i]] + w[i]) ,但是由于这里代表N的维度没有了,
* 造成dp[i-1][j-v[i]][k-m[i]]被提前更新为了dp[i][j-v[i]][k-m[i]],这样拿到的数据是错误的,最后的结果也是错误的
* (这样做的效果,实际上等于计算了一个二维约束下的完全背包问题,而不是二维约束下的01背包问题)
*
* 通过改变 j 和 k 的遍历顺序,保证在更新dp[j][k]时,dp[j-v[i]][k-m[i]]实际上还是dp[i-1][j-v[i]][k-m[i]],
* 即 V 上小于 v ,M 上小于 k 的值,都没有更新过,还是之前的状态(i-1的状态),达到正确缩减维度的效果
*/
}
链接:https://www.acwing.com/solution/content/1704/分组背包问题
每件物品的体积是 vij,价值是 wij,其中 i 是组号,j 是组内编号。
第一行有两个整数 N,V,用空格隔开,分别表示物品组数和背包容量。
每组数据接下来有 Si 行,每行有两个整数 vij,wij,用空格隔开,分别表示第 i 个物品组的第 j 个物品的体积和价值;
输出格式
输出一个整数,表示最大价值。
0
3 5
2
1 2
2 4
1
3 4
1
4 5
输出样例:
8solution
import java.util.*;
class Main {
Scanner sc = new Scanner(System.in);
int maxV = 105;
int maxN = 105;
int N, M, V;
int[] dp = new int[maxV];
int[] v = new int[maxN];
int[] w = new int[maxN];
void run() {
N = sc.nextInt(); V = sc.nextInt();
for (int i = 0; i < N; i++) {
M = sc.nextInt();
for (int j = 0; j < M; j++) {
v[j] = sc.nextInt();
w[j] = sc.nextInt();
}
for (int j = V; j >= 0; j--) {
for (int k = 0; k < M; k++) {
if (j >= v[k]) dp[j] = Math.max(dp[j], dp[j - v[k]] + w[k]);
}
}
}
System.out.println(dp[V]);
}
public static void main(String[] args) {
Main m = new Main();
m.run();
}
}
作者:Aranne
链接:https://www.acwing.com/solution/content/15853/
来源:AcWing
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。