背包问题——多重背包

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/wdays83892469/article/details/79770227

多重背包

多重背包是介于01背包和完全背包之间:
有容积为V的背包,我们给定一些物品,每种物品包含体积w,价值v和数量k,
求用该背包能装下的最大价值总量。
与之前的背包问题都不同,每种物品可选数量不再为无穷多或者1,而是介于其中的一个确定数k
我们可以将多重背包问题转化到01背包上去,即每种物品均被视为k种不同的物品,不过这样时间复杂度较高
我们可以选择有技巧的拆分。将原数量为k的物品分成若干组,魅族物品看成一件物品,其价值和重量为该组中
所有的价值的总和
每组物品包含的原物品个数分别为 1、2、4、…k-2^c+1,其中c为使k-2^c大于0的最大整数。
这种类似二进制的拆分,不仅将物品数量大大降低,同时通过对这些若干个原物品组合得到的新物品的不同组合,
可以得到0到k之间任意件物品的价值重量和,对这些新的物品做01背包,即可得到多重背包问题的解。

珍惜现在,感恩生活(九度103题)

单输入输出版
题目描述:
为了挽救灾区同胞的生命,心系灾区的你准备自己采购一些粮食支援灾区,现假设你一共有资金n元,
而市场有m种大米,每种大米都是袋装产品,其价格不等,并且只能整袋采购。请问你用有限的资金最多
采购多少大米呢?

输入:
第一行两个整数n和m(1 <= n <= 100,1<=m <=100),分别表示经费的金额和大米的种类,
然后m行数据,每行包括三个数w,v,k(1 <= w <= 20,1<= v <=200 ,1<=k <=20)
分别对应每袋的价格,每袋的重量,对应大米袋数

输出:
请输出能购买大米的最大重量,可以假设经费买不光所有大米,并且经费可以不用完。

转化为01背包问题

public class Main {
    public static void main(String[] args) {
        Scanner input=new Scanner(System.in);
        int s=input.nextInt();
        int n=input.nextInt();
        int W[]=new int[100001];
        int V[]=new int[100001];
        int dp[]=new int[100001];
        int w_index=0;
        int v_index=0;
        for (int i = 1; i <= n; i++) {
            int w=input.nextInt();
            int v=input.nextInt();
            int k=input.nextInt();
            for (int j = 0; j <k; j++) {
                W[w_index]=w;
                V[v_index]=v;
                w_index++;
                v_index++;
            }

        }
        for (int i = 0; i < W.length; i++) {
            for (int j = s; j >= W[i]; j--) {
                dp[j]=Math.max(dp[j], dp[j-W[i]]+V[i]);
            }
        }
        System.out.println(dp[s]);

    }

}
public class 多重背包问题优化解 {
    static int W[] = new int[2001];
    static int V[] = new int[2001];
    static int num[] = new int[2001];
    static int dp[] = new int[2001];

    public static void main(String[] args) {
        Scanner input = new Scanner(System.in);
        int n = input.nextInt();
        int m = input.nextInt();
        int cnt = 0;// 拆分后的物品总数
        for (int i = 1; i <= m; i++) {
            int w = input.nextInt();
            int v = input.nextInt();
            int k = input.nextInt();
            int c = 1;
            while (k - c > 0) {// 对输出的数字k,拆分成1,2,4...k-2^c+1,其中c为使最后一项>0的最大整数
                k -= c;
                W[++cnt] = c * w;
                // cnt++;
                V[cnt] = c * v;// 拆分后的大米重量和价格均为组成该物品的大米的重量价格和
                c *= 2;

            }
            W[++cnt] = w * k;
            // cnt;
            V[cnt] = v * k;
        }
        // init dp[] dp fill in 0 默认就是0,可以省略
        for (int i = 1; i <= n; i++) {
            dp[i] = 0;
        }
        for (int i = 1; i <= cnt; i++) {
            for (int j = n; j >= W[i]; j--) {
                dp[j] = Math.max(dp[j], dp[j - W[i]] + V[i]);
            }
        }
        System.out.println(dp[n]);

    }
}

猜你喜欢

转载自blog.csdn.net/wdays83892469/article/details/79770227