01背包问题(Java)

题目

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

第 i 件物品的体积是 vi,价值是 wi。

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

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

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

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

数据范围
0<N,V≤1000
0<vi,wi≤1000
输入样例
4 5
1 2
2 4
3 4
4 5
输出样例:
8

思想

经典动态规划题
物品个数n,背包总容量v
c[]代表每个物品体积,w[]代表每个物品价值
设f[i][j],表示前i件物品放入容量为j的背包的最大价值
因此可遍历物品,并计算假设容量为j时候的最大值。
此时有两种情况:
1.容量不够(j < c[i]),则取不了当前物品,直接f[i][j]=f[i-1][j]
2.容量够,则需要判断取与不取当前物品的价值
若不取第i件,问题转化为求前i-1件物品放入容量为v的背包的问题,即f[i][j]=f[i-1][j]
若取第i件,问题转化为求前i-1件物品放入容量为j-c[i]的背包的问题,即f[i][j]=f[i-1][j-c[i]]+w[i]
所以f[i][j]即是求以上两种情况的最大值,最终状态转移方程是 f[i][v] = max(f[i-1][v], f[i-1][j-c[i]] + w[i])
最后答案就是f[n][v]

代码实现

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[] v = new int[N + 1];
        int[] w = new int[N + 1];
        for(int i=1; i<=N; i++) {
            v[i] = sc.nextInt();
            w[i] = sc.nextInt();
        }

        System.out.println(cal(N, V, w, v));
    }

    /**
     * 求01背包的解
     * @param n 物品个数
     * @param v 背包总容量
     * @param w 每个物品的价值,注意下标从1开始
     * @param c 每个物品的体积,注意下标从1开始
     * @return
     */
    private static int cal(int n, int v, int[] w, int[] c) {
        /*
           
         */

        if (n == 0 || v == 0) return 0;
        if (w == null || w.length == 0) return 0;
        if (c == null || c.length == 0) return 0;


        int[][] f = new int[n + 1][v + 1];
        for(int i=1; i<=n; i++) {
            for(int j=1;j<=v;j++) {
                f[i][j] = j<c[i]? f[i-1][j] : Math.max(f[i-1][j], f[i-1][j-c[i]] + w[i]);
            }
        }

        return f[n][v];
    }
}

posted @ 2019-07-02 15:34  TatuCz  阅读(980)  评论(0编辑  收藏  举报