背包九讲笔记--多重背包问题(内附代码实现)

背包九讲–多重背包问题

前言:最近在看背包九讲,记一下笔记顺便将其中的代码实现一下

在这里插入图片描述
在这里插入图片描述
这个多重背包的问题较好理解,完全背包问题是物品不限次的拿,而多重背包问题是物品有限次的拿,因此当物品的重量乘以物品的个数大于总背包重量时,相当于完全背包问题,否则就通过01背包问题来解决

代码实现:

01背包问题实现

public class PackageProblem01 {
    public void PackageProblem02Solution(int[] dp, int C, int W, int weight)
    {
        int i;
        for(i=weight; i>=C; i--)
                dp[i] = Math.max(dp[i], dp[i-C]+W);
    }
}

完全背包问题实现

public class PackageProblem02 {
    public void PackageProblem02Solution(int[] dp, int C, int W, int weight)
    {
        int i;
        for(i=C; i<=weight; i++)
                dp[i] = Math.max(dp[i], dp[i-C]+W);
    }
}

多重背包问题实现

import java.util.Arrays;

public class MultiplePack {
    private PackageProblem01 p01 = new PackageProblem01();
    private PackageProblem02 p02 = new PackageProblem02();
    public void MulitplePcakSolution(int[] dp, int M, int W, int C, int V)
    {
        if(M*C>=V)
        {
            p02.PackageProblem02Solution(dp, C, W, V);
            return;
        }
        int k=1;
        while(k<M)
        {
            p01.PackageProblem02Solution(dp, k*C,k*W, V);
            M = M - k;
            k = 2*k;
        }
        p01.PackageProblem02Solution(dp, M*C, M*W, V);
            
        
    }
    public static void main(String[] args) {
        int V = 15;
        int[] M = {1,3,5,7,9};
        int[] C = {1,3,5,7,9};
        int[] W = {1,3,5,7,9};
        int[] dp = new int[V+1];
        int i;
        MultiplePack m = new MultiplePack();
        for(i=0; i<M.length; i++)
        {
            m.MulitplePcakSolution(dp, M[i], W[i], C[i], V);
            System.out.println(Arrays.toString(dp));
        }
    }
}

可以观察一下输出结果

[0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1]
[0, 1, 1, 3, 4, 4, 6, 7, 7, 9, 10, 10, 10, 10, 10, 10]
[0, 1, 1, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15]
[0, 1, 1, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15]
[0, 1, 1, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15]

可行性问题 O(VN)的算法

这个伪代码一开始看很晕,感觉不知所云

F[0, 1 . . . V ] ← −1
F[0, 0] ← 0
for i ← 1 to N
    for j ← 0 to V
    if F[i − 1][j] ≥ 0
        F[i][j] = M[i]
    else
        F[i][j] = −1
    for j ← 0 to V − Ci
        if F[i][j] > 0
            F[i][j + Ci] ← max{F[i][j + Ci], F[i][j] − 1}

但是我们根据F[i][j]的含义来理解代码就会更清楚一点,F[i][j]表示的是使用前i种物品填满容量为j的背包时第i种物品所剩下的最大个数

首先,初始化

F[0, 1 . . . V ] ← −1
F[0, 0] ← 0

这段代码表示,使用0种物品没办法填装满容量大于1的背包,但是可以填满容量为0的背包


第一层循环

for i ← 1 to N

表示由前几种物品组合,从1开始累加


第二层循环其一

for j ← 0 to V
    if F[i − 1][j] ≥ 0
        F[i][j] = M[i]
    else
        F[i][j] = −1

这段代码表示从0开始增加容量时,如果前i-1种物品没有填满,有两种情况,第一种是背包不合适,也就是一个物品都装不下,那这个时候肯定就不考虑了,直接将F[i][j]=-1,另外一种情况就是前面所有物品都放下去了还填不满容量为j的背包,这种情况下面的代码会进行补偿


第二层循环其二

for j ← 0 to V − Ci
    if F[i][j] > 0
        F[i][j + Ci] ← max{F[i][j + Ci], F[i][j] − 1}

这段代码就表示将一个当前物品假如背包后,所剩物品的个数应该为F[i][j+ci]和当前物品数减1的更大者

Java实现算法

import java.util.Arrays;

public class MultiplePack {
	public static void main(String[] args) {
		int V = 10;
		int[] M = {0,3,4,6,9};
		int[] C = {0,3,4,6,9};
		int[][] dp = new int[M.length][V+1];
		int i, j;
		for(i=0; i<dp.length; i++)
			Arrays.fill(dp[i], -1);
		dp[0][0] = 0;
		for(i=1; i<M.length; i++)
		{
			for(j=0; j<=V; j++)
			{
				if(dp[i-1][j]>=0)
					dp[i][j]=M[i];
				else
					dp[i][j] = -1;
			}
			for(j=0; j<=V-C[i]; j++)
			{
				if(dp[i][j]>0)
					dp[i][j+C[i]] = Math.max(dp[i][j+C[i]], dp[i][j]-1);
			}
			for(j=0; j<dp.length; j++)
				System.out.println(Arrays.toString(dp[j]));
			System.out.println("--------------------");
		}
		
	}
}

我们看一下输出结果,观察一下dp数组的变化

[0, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1]
[3, -1, -1, 2, -1, -1, 1, -1, -1, 0, -1]
[-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1]
[-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1]
[-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1]
--------------------
[0, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1]
[3, -1, -1, 2, -1, -1, 1, -1, -1, 0, -1]
[4, -1, -1, 4, 3, -1, 4, 3, 2, 4, 3]
[-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1]
[-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1]
--------------------
[0, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1]
[3, -1, -1, 2, -1, -1, 1, -1, -1, 0, -1]
[4, -1, -1, 4, 3, -1, 4, 3, 2, 4, 3]
[6, -1, -1, 6, 6, -1, 6, 6, 6, 6, 6]
[-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1]
--------------------
[0, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1]
[3, -1, -1, 2, -1, -1, 1, -1, -1, 0, -1]
[4, -1, -1, 4, 3, -1, 4, 3, 2, 4, 3]
[6, -1, -1, 6, 6, -1, 6, 6, 6, 6, 6]
[9, -1, -1, 9, 9, -1, 9, 9, 9, 9, 9]
--------------------

我觉得我理解的还不是很深,但是看着这个变化大概能理解,你们也可以观察一下这个dp数组的变化

参考:
《背包九讲》

猜你喜欢

转载自blog.csdn.net/jump_into_zehe/article/details/106794982