动态规划:分组背包问题

文章目录

  • 往期
    • 题目
    • 解题思路
      • 空间优化
    • Reference


往期

  1. 01背包问题
  2. 完全背包问题
  3. 多重背包问题I
  4. 多重背包问题II
  5. 混合背包问题
  6. 二维费用背包问题

题目

分组背包问题

N N N 组物品和一个容量是 V V V 的背包。

每组物品有若干个,同一组内的物品最多只能选一个。
每件物品的体积是 v i j v_{ij} vij,价值是 w i j w_{ij} wij,其中 i i i 是组号, j j j 是组内编号。

求解将哪些物品装入背包,可使物品总体积不超过背包容量,且总价值最大。

输出最大价值。

输入格式

第一行有两个整数 N , V N,V N,V,用空格隔开,分别表示物品组数和背包容量。

接下来有 N N N 组数据:

  • 每组数据第一行有一个整数 S i S_{i} Si,表示第 i i i 个物品组的物品数量;
  • 每组数据接下来有 S i S_{i} Si 行,每行有两个整数 v i j , w i j v_{ij},w_{ij} vij,wij,用空格隔开,分别表示第 i i i 个物品组的第 j j j 个物品的体积和价值;

输出格式

输出一个整数,表示最大价值。

数据范围

0 < N , V ≤ 100 00<N,V100
0 < S i ≤ 100 00<Si100
0 < v i j , w i j ≤ 100 00<vij,wij100

输入样例

3 5
2
1 2
2 4
1
3 4
1
4 5

输出样例:

8

解题思路

01背包问题中每种物品有两种策略:选或者不选,本题变成了每组物品有两种策略:选择本组的一件或者一件都不选。

  1. 状态定义

d p [ i ] [ j ] dp[i][j] dp[i][j]: 前 i i i组物品花费费用 j j j能取得的最大价值

  1. 状态转移方程

d p [ i ] [ j ] = m a x [ d p [ i − 1 ] [ j ] , d p [ i − 1 ] [ j − v [ i ] [ k ] ] + w [ i ] [ k ] ] dp[i][j] = max\left[ dp[i-1][j], dp[i-1][j-v[i][k]] + w[i][k]\right] dp[i][j]=max[dp[i1][j],dp[i1][jv[i][k]]+w[i][k]]

import java.util.*;

class Main {
     
    private static final int S = 110;
    public static void main(String[] args) {
     
        Scanner sc = new Scanner(System.in);
        
        int N = sc.nextInt();           // 物品组数
        int C = sc.nextInt();           // 背包容量
        
        int[][] v = new int[N+1][S];    // 物品体积
        int[][] w = new int[N+1][S];    // 物品价值
        int[] s = new int[N+1];         // 每组物品数量
        for (int i = 1; i <= N; i++) {
     
            s[i] = sc.nextInt();
            for (int j = 0; j < s[i]; j++) {
     
                v[i][j] = sc.nextInt();
                w[i][j] = sc.nextInt();
            }
        }
        
        int[][] dp = new int[N+1][C+1];
        
        for (int i = 1; i <= N; i++) {
     
            for (int j = 1; j <= C; j++) {
     
                dp[i][j] = dp[i-1][j];           // 不选第i组物品
                for (int k = 0; k < s[i]; k++) {
      // 第i组物品中选一件
                    if (j >= v[i][k]) {
     
                        dp[i][j] = Math.max(dp[i][j], dp[i-1][j-v[i][k]] + w[i][k]);
                    }
                }
            }
        }
        System.out.println(dp[N][C]);
    }
}

空间优化

类似01背包问题中空间优化,可将本题的二维dp数组优化为一维数组,仿照01背包的套路逆向枚举体积

import java.io.*;
import java.util.*;

public class Main {
     
    private static final int S = 110;
    public static void main(String[] args) {
     
        Scanner sc = new Scanner(System.in);

        int N = sc.nextInt();            // 物品组数
        int C = sc.nextInt();            // 背包容积

        int[][] v = new int[N+1][S];        // 体积
        int[][] w = new int[N+1][S];        // 价值
        int[] s = new int[N+1];

        for (int i = 1; i <= N; i++) {
     
            s[i] = sc.nextInt();
            for (int j = 0; j < s[i]; j++) {
     
                v[i][j] = sc.nextInt();
                w[i][j] = sc.nextInt();
            }
        }

        int[] dp = new int[C+1];
        for (int i = 1; i <= N; i++) {
     
            for (int j = C; j >= 0; j--) {
     
                for (int k = 0; k < s[i]; k++) {
     
                    if(j>=v[i][k]) {
     
                        dp[j] = Math.max(dp[j], dp[j - v[i][k]] + w[i][k]);
                    }
                }
            }
        }
        System.out.println(dp[C]);
    }
}

Reference

  1. 背包问题九讲

  2. 分组背包问题

你可能感兴趣的:(数据结构与算法,动态规划,算法,java)