傅芳杰

个人博客

You Deserve The Best


背包问题

01背包问题

ydTTJI.png

完全背包问题

ydT7Wt.png

多重背包问题

yd7rnS.png

分组背包问题

yd7s0g.png

AcWing 2. 01背包问题 原题链接

有 NN 件物品和一个容量是 VV 的背包。每件物品只能使用一次。

第 ii 件物品的体积是 vivi,价值是 wiwi。

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

输入格式

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

接下来有 NN 行,每行两个整数 vi,wivi,wi,用空格隔开,分别表示第 ii 件物品的体积和价值。

输出格式

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

数据范围

0<N,V≤10000<N,V≤1000 0<vi,wi≤10000<vi,wi≤1000

输入样例

4 5
1 2
2 4
3 4
4 5

输出样例:

8

朴素写法:

    private static int function1() {
        int n = in.nextInt();
        int m = in.nextInt();
        int[][] a = new int[n][2];
        for (int i = 0; i < n; i++) {
            a[i][0] = in.nextInt();
            a[i][1] = in.nextInt();
        }

        int[][] dp = new int[n + 1][m + 1];
        for (int i = 1; i < n + 1; i++) {
            for (int j = 0; j < m + 1; j++) {
                if (j >= a[i - 1][0])
                    dp[i][j] = Math.max(dp[i - 1][j], dp[i - 1][j - a[i - 1][0]] + a[i - 1][1]);
                else
                    dp[i][j] = dp[i - 1][j];
            }
        }
        return dp[n][m];
    }

空间优化写法:

    private static int function2() {
        int n = in.nextInt();
        int m = in.nextInt();
        int[][] a = new int[n][2];
        for (int i = 0; i < n; i++) {
            a[i][0] = in.nextInt();
            a[i][1] = in.nextInt();
        }

        int[] dp = new int[m + 1];
        for (int i = 1; i < n + 1; i++) {
            for (int j = m; j >= a[i - 1][0]; j--) {
                    dp[j] = Math.max(dp[j], dp[j - a[i - 1][0]] + a[i - 1][1]);
            }
        }
        return dp[m];
    }

AcWing 3. 完全背包问题 原题链接

有 NN 种物品和一个容量是 VV 的背包,每种物品都有无限件可用。

第 ii 种物品的体积是 vivi,价值是 wiwi。

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

输入格式

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

接下来有 NN 行,每行两个整数 vi,wivi,wi,用空格隔开,分别表示第 ii 种物品的体积和价值。

输出格式

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

数据范围

0<N,V≤10000<N,V≤1000 0<vi,wi≤10000<vi,wi≤1000

输入样例

4 5
1 2
2 4
3 4
4 5

输出样例:

10

朴素写法:

    private static int function1() {
        int n = in.nextInt();
        int m = in.nextInt();
        int[][] a = new int[n][2];
        for (int i = 0; i < n; i++) {
            a[i][0] = in.nextInt();
            a[i][1] = in.nextInt();
        }

        int[][] dp = new int[n + 1][m + 1];
        for (int i = 1; i < n + 1; i++) {
            for (int j = 0; j < m + 1; j++) {
                for (int k = 0; k * a[i - 1][0] <= j; k++)
                    dp[i][j] = Math.max(dp[i][j], dp[i - 1][j - k * a[i - 1][0]] + k * a[i - 1][1]);
            }
        }
        return dp[n][m];
    }

维度优化写法:

    private static int function2() {
        int n = in.nextInt();
        int m = in.nextInt();
        int[][] a = new int[n][2];
        for (int i = 0; i < n; i++) {
            a[i][0] = in.nextInt();
            a[i][1] = in.nextInt();
        }

        int[][] dp = new int[n + 1][m + 1];
        for (int i = 1; i < n + 1; i++) {
            for (int j = 0; j < m + 1; j++) {
                if (j >= a[i - 1][0])
                    dp[i][j] = Math.max(dp[i - 1][j], dp[i][j - a[i - 1][0]] + a[i - 1][1]);
                else dp[i][j] = dp[i - 1][j];
            }
        }
        return dp[n][m];
    }

维度+空间优化写法

    private static int function3() {
        int n = in.nextInt();
        int m = in.nextInt();
        int[][] a = new int[n][2];
        for (int i = 0; i < n; i++) {
            a[i][0] = in.nextInt();
            a[i][1] = in.nextInt();
        }
        int[] dp = new int[m + 1];
        for (int i = 1; i < n + 1; i++) {
            for (int j = a[i - 1][0]; j < m + 1; j++) {
                dp[j] = Math.max(dp[j], dp[j - a[i - 1][0]] + a[i - 1][1]);
            }
        }
        return dp[m];
    }

AcWing 4. 多重背包问题 原题链接

有 NN 种物品和一个容量是 VV 的背包。

第 ii 种物品最多有 sisi 件,每件体积是 vivi,价值是 wiwi。

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

输入格式

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

接下来有 NN 行,每行三个整数 vi,wi,sivi,wi,si,用空格隔开,分别表示第 ii 种物品的体积、价值和数量。

输出格式

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

数据范围

0<N,V≤1000<N,V≤100 0<vi,wi,si≤1000<vi,wi,si≤100

输入样例

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

输出样例:

10

朴素写法:

    private static int function1() {
        int n = in.nextInt();
        int m = in.nextInt();
        int[][] a = new int[n][3];
        for (int i = 0; i < n; i++) {
            a[i][0] = in.nextInt();
            a[i][1] = in.nextInt();
            a[i][2] = in.nextInt();
        }
        int[][] dp = new int[n + 1][m + 1];
        for (int i = 1; i < n + 1; i++) {
            for (int j = 0; j < m + 1; j++) {
                for (int k = 0; k <= a[i - 1][2] && j >= k * a[i - 1][0]; k++)
                    dp[i][j] = Math.max(dp[i][j], dp[i - 1][j - k * a[i - 1][0]] + k * a[i - 1][1]);
            }
        }
        return dp[n][m];
    }

二进制优化写法:

    private static int function2() {
        int n = in.nextInt();
        int m = in.nextInt();
        int[][] a = new int[n][3];
        //b的长度是n*logn
        int[][] b = new int[25000][2];
        for (int i = 0; i < n; i++) {
            a[i][0] = in.nextInt();
            a[i][1] = in.nextInt();
            a[i][2] = in.nextInt();
        }
        int idx = 0;
        for (int i = 0; i < n; i++) {
            int k = 1;
            while (k <= a[i][2]) {
                b[idx][0] = a[i][0] * k;
                b[idx][1] = a[i][1] * k;
                a[i][2] -= k;
                k <<= 1;
                idx++;
            }
            if (a[i][2] > 0) {
                b[idx][0] = a[i][0] * a[i][2];
                b[idx][1] = a[i][1] * a[i][2];
                idx++;
            }
        }
        int[] dp = new int[m + 1];
        for (int i = 1; i < idx + 1; i++) {
            for (int j = m; j >= b[i - 1][0]; j--) {
                dp[j] = Math.max(dp[j], dp[j - b[i - 1][0]] + b[i - 1][1]);
            }
        }
        return dp[m];
    }

AcWing 5. 多重背包问题 II 原题链接

有 NN 种物品和一个容量是 VV 的背包。

第 ii 种物品最多有 sisi 件,每件体积是 vivi,价值是 wiwi。

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

输入格式

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

接下来有 NN 行,每行三个整数 vi,wi,sivi,wi,si,用空格隔开,分别表示第 ii 种物品的体积、价值和数量。

输出格式

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

数据范围

0<N≤10000<N≤1000 0<V≤20000<V≤2000 0<vi,wi,si≤20000<vi,wi,si≤2000

提示:

本题考查多重背包的二进制优化方法。

输入样例

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

输出样例:

10
    private static int function() {
        int n = in.nextInt();
        int m = in.nextInt();
        int[][] a = new int[n][3];
        //b的长度是n*logn
        int[][] b = new int[25000][2];
        for (int i = 0; i < n; i++) {
            a[i][0] = in.nextInt();
            a[i][1] = in.nextInt();
            a[i][2] = in.nextInt();
        }
        int idx = 0;
        for (int i = 0; i < n; i++) {
            int k = 1;
            while (k <= a[i][2]) {
                b[idx][0] = a[i][0] * k;
                b[idx][1] = a[i][1] * k;
                a[i][2] -= k;
                k <<= 1;
                idx++;
            }
            if (a[i][2] > 0) {
                b[idx][0] = a[i][0] * a[i][2];
                b[idx][1] = a[i][1] * a[i][2];
                idx++;
            }
        }
        int[] dp = new int[m + 1];
        for (int i = 1; i < idx + 1; i++) {
            for (int j = m; j >= b[i - 1][0]; j--) {
                dp[j] = Math.max(dp[j], dp[j - b[i - 1][0]] + b[i - 1][1]);
            }
        }
        return dp[m];
    }

AcWing 9. 分组背包问题 原题链接

有 NN 组物品和一个容量是 VV 的背包。

每组物品有若干个,同一组内的物品最多只能选一个。 每件物品的体积是 vijvij,价值是 wijwij,其中 ii 是组号,jj 是组内编号。

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

输出最大价值。

输入格式

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

接下来有 NN 组数据:

  • 每组数据第一行有一个整数 SiSi,表示第 ii 个物品组的物品数量;
  • 每组数据接下来有 SiSi 行,每行有两个整数 vij,wijvij,wij,用空格隔开,分别表示第 ii 个物品组的第 jj 个物品的体积和价值;

输出格式

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

数据范围

0<N,V≤1000<N,V≤100 0<Si≤1000<Si≤100 0<vij,wij≤1000<vij,wij≤100

输入样例

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

输出样例:

8

朴素写法:

    private static class Packet {
        int weight;
        int value;

        public Packet(int weight, int value) {
            this.weight = weight;
            this.value = value;
        }
    }    
	private static int function1() {
        int n = in.nextInt();
        int m = in.nextInt();
        Packet[][] a = new Packet[n][];
        int[] size = new int[n];
        for (int i = 0; i < n; i++) {
            int s = in.nextInt();
            size[i] = s;
            a[i] = new Packet[s];
            for (int j = 0; j < s; j++) {
                a[i][j] = new Packet(in.nextInt(), in.nextInt());
            }
        }
        int[][] dp = new int[n + 1][m + 1];
        for (int i = 1; i < n + 1; i++) {
            for (int j = 0; j < m + 1; j++) {
                // 这一组可以一种也不选
                dp[i][j] = dp[i - 1][j];
                for (int k = 0; k < size[i - 1]; k++) {
                    if (j >= a[i - 1][k].weight)
                        dp[i][j] = Math.max(dp[i][j], dp[i - 1][j - a[i - 1][k].weight] + a[i - 1][k].value);
                }
            }
        }
        return dp[n][m];
    }

空间优化写法:

     private static class Packet {
        int weight;
        int value;

        public Packet(int weight, int value) {
            this.weight = weight;
            this.value = value;
        }
    }
	private static int function2() {
        int n = in.nextInt();
        int m = in.nextInt();
        Packet[][] a = new Packet[n][];
        int[] size = new int[n];
        for (int i = 0; i < n; i++) {
            int s = in.nextInt();
            size[i] = s;
            a[i] = new Packet[s];
            for (int j = 0; j < s; j++) {
                a[i][j] = new Packet(in.nextInt(), in.nextInt());
            }
        }
        int[] dp = new int[m + 1];
        for (int i = 1; i < n + 1; i++) {
            for (int j = m; j >= 0; j--) {
                for (int k = 0; k < size[i - 1]; k++) {
                    if (j >= a[i - 1][k].weight)
                        dp[j] = Math.max(dp[j], dp[j - a[i - 1][k].weight] + a[i - 1][k].value);
                }
            }
        }
        return dp[m];
    }