背包问题

背包问题主要由三类:

  1. 01背包
  2. 完全背包
  3. 多重背包

 

1、01背包(使用滚动数组优化)

import java.util.*;

public class Main {
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        int t = sc.nextInt();
        for (int k = 1; k <= t; k++) {
            int N = sc.nextInt();   // 商品个数
            int V = sc.nextInt();   // 总花销

            int[] cost = new int[N];    // 单个花销
            int[] val = new int[N];     // 单个价值

            for (int  i = 0; i < N; i++) val[i] = sc.nextInt();
            for (int  i = 0; i < N; i++) cost[i] = sc.nextInt();

            int[] dp = new int[V+1];

            // 初始化
            for (int i = 0; i <= V; i++) dp[i] = 0;

            for (int i = 1; i <= N; i++) {
                ZeroOnePack(dp, V, cost[i-1], val[i-1]);
            }

            System.out.printf("%d%n", dp[V]);
        }
    }

    public static void ZeroOnePack(int[] dp, int V, int C, int W) {
        for (int i = V; i >= C; i--) {
            dp[i] = Math.max(dp[i], dp[i-C] + W);
        }
    }
}

 


 

2、完全背包

// 完全背包
    // 状态转移方程:F[i,v] = max{F[i-1,v], F[i,v-Ci] + Wi}  v -> Ci..V
    public static void CompletePark(int[] dp, int V, int C, int W) {
        for (int i = C; i <= V; i++) {
            dp[i] = Math.max(dp[i], dp[i-C] + W);
        }
    }

例题HDU1114

import java.util.*;

public class Main {
    static final int MAXN = 0x3f3f3f3f;

    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        int t = sc.nextInt();
        for (int k = 1; k <= t; k++) {
            int minV = sc.nextInt();
            int maxV = sc.nextInt();
            int V = maxV - minV;    // 总花销

            int N = sc.nextInt();   // 商品的种类数量

            int[] cost = new int[N];    // 单个花销
            int[] val = new int[N];     // 单个价值

            for (int  i = 0; i < N; i++) {
                val[i] = sc.nextInt();
                cost[i] = sc.nextInt();
            }

            int[] dp = new int[V+1];
            // 求背包装满的情况下,总背包的最小值
            Arrays.fill(dp, MAXN);
            dp[0] = 0;

            for (int i = 1; i <= N; i++) {
                CompletePark(dp, V, cost[i-1], val[i-1]);
            }

            if(dp[V] != MAXN) System.out.printf("The minimum amount of money in the piggy-bank is %d.%n", dp[V]);
            else System.out.printf("This is impossible.%n");
        }
    }

    // 完全背包
    // 状态转移方程:F[i,v] = max{F[i-1,v], F[i,v-Ci] + Wi}  v -> Ci..V
    public static void CompletePark(int[] dp, int V, int C, int W) {
        for (int i = C; i <= V; i++) {
            dp[i] = Math.min(dp[i], dp[i-C] + W);
        }
    }
}

 


 

 

3、多重背包

// 多重背包
    public static void MultiplePack(int[] dp, int V, int C, int  W, int M) {
        if (C * M >= V) {
            CompletePark(dp, V, C, W);
        }
        else {
            // 使用二进制转换为0-1背包
            // 1 + 2^1 + 2^2 + ... + 2^(k-1) + (M - 2^k + 1) = M
            int k = 1;
            while (k < M) {
                ZeroOnePack(dp, V, k*C, k*W);
                M -= k;
                k <<= 1;
            }
            if (M > 0) {    // 如果M有剩余,可以转化为1个价值为M*W,重量为M*C的物品,转化为01背包问题
                ZeroOnePack(dp, V, M*C, M*W);
            }
        }
    }

HDU2191

import java.util.*;

public class Main {
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        int t = sc.nextInt();
        for (int k = 1; k <= t; k++) {
            int V = sc.nextInt();   // 总金额
            int N = sc.nextInt();   // 商品的种类数量

            int[] cost = new int[N];    // 单个花销
            int[] val = new int[N];     // 单个价值
            int[] num = new int[N];     // 单个物品的数量

            for (int  i = 0; i < N; i++) {
                cost[i] = sc.nextInt();
                val[i] = sc.nextInt();
                num[i] = sc.nextInt();
            }

            int[] dp = new int[V+1];
            for (int i = 0; i <= V; i++) dp[i] = 0;

            for (int i = 1; i <= N; i++) {
                MultiplePack(dp, V, cost[i-1], val[i-1], num[i-1]);
            }

            System.out.printf("%d%n", dp[V]);
        }
    }

    public static void ZeroOnePack(int[] dp, int V, int C, int W) {
        for (int i = V; i >= C; i--) {
            dp[i] = Math.max(dp[i], dp[i-C] + W);
        }
    }

    // 完全背包
    // 状态转移方程:F[i,v] = max{F[i-1,v], F[i,v-Ci] + Wi}  v -> Ci..V
    public static void CompletePark(int[] dp, int V, int C, int W) {
        for (int i = C; i <= V; i++) {
            dp[i] = Math.max(dp[i], dp[i-C] + W);
        }
    }

    // 多重背包
    public static void MultiplePack(int[] dp, int V, int C, int  W, int M) {
        if (C * M >= V) {
            CompletePark(dp, V, C, W);
        }
        else {
            // 使用二进制转换为0-1背包
            // 1 + 2^1 + 2^2 + ... + 2^(k-1) + (M - 2^k+ 1) = M
            int k = 1;
            while (k < M) {
                ZeroOnePack(dp, V, k*C, k*W);
                M -= k;
                k <<= 1;
            }
            if (M > 0) {    // 如果M有剩余,可以转化为1个价值为M*W,重量为M*C的01背包问题
                ZeroOnePack(dp, V, M*C, M*W);
            }
        }
    }
}

 

posted @ 2021-08-22 12:44  Peterxiazhen  阅读(38)  评论(0编辑  收藏  举报