Java实现背包问题之01背包(是否装满),完全背包

哎,以前算法没有学好,现在找工作笔试动态规划又是必考,其中背包问题又经常遇见,今天给大家介绍几种常见的背包问题。如有误解请大家指导,谢谢。

先说一下算法的主要思想,利用动态规划来解决。每次遍历到的第i个物品,根据w[i]和v[i]来确定是否需要将该物品放入背包中。即对于给定的n个物品,设v[i]、w[i]分别为第i个物品的价值和重量,maxw为背包的容量。再令v[i][j]表示在前i个物品中能够装入容量为j的背包中的最大价值。则我们有下面的结果:

(1)v[i][0]=v[0][j]=0;

(2)v[i][j]=v[i-1][j] 当w[i]>j

(3)v[i][j]=max{v[i-1][j],v[i-1][j-w[i]]+v[i]} 当j>=w[i]

好的,我们的算法就是基于此三个结论式。

01背包(二维数组求解):

public class _01背包 {
    public static void main(String[] args) {
        int[] w = {2,1,6,4,3};//物品重量
        int[] v = {4,3,5,1,2};//物品价值
        int maxw = 12;//背包容量
        int len = v.length;//物品个数
        int[][] f = new int[len+1][maxw+1];
        int i,j;
        for(i = 1; i < f.length; i++)
        {
            for(j = 1; j < f[0].length; j++)
            {
                if(w[i-1] > j)
                    f[i][j] = f[i-1][j];
                else {
                    if(f[i-1][j] < f[i-1][j-w[i-1]] + v[i-1])
                    {
                        f[i][j] = f[i-1][j-w[i-1]] + v[i-1];
                    }
                    else {
                        f[i][j] = f[i-1][j];
                    }
                }
            }
        }
        for(i = 0; i < f.length; i++)
        {
            for(j = 0; j < f[0].length; j++)
                System.out.print(f[i][j] + " ");
            System.out.println();
        }
    }
}

如果题目要求给出是哪几个物品放入其中,则我们在代码里面加入一个标记数组:

public class sf {

    public static void main(String[] args) {
        // TODO Auto-generated method stub
        int[] weight = {3,5,2,6,4}; //物品重量
        int[] val = {4,4,3,5,3}; //物品价值
        int m = 12; //背包容量
        int n = val.length; //物品个数

        int[][] f = new int[n+1][m+1]; //f[i][j]表示前i个物品能装入容量为j的背包中的最大价值
        int[][] path = new int[n+1][m+1];
        //初始化第一列和第一行
        for(int i=0;i<f.length;i++){
            f[i][0] = 0;
        }
        for(int i=0;i<f[0].length;i++){
            f[0][i] = 0;
        }
        //通过公式迭代计算
        for(int i=1;i<f.length;i++){
            for(int j=1;j<f[0].length;j++){
                if(weight[i-1]>j)
                    f[i][j] = f[i-1][j];
                else{
                    if(f[i-1][j]<f[i-1][j-weight[i-1]]+val[i-1]){
                        f[i][j] = f[i-1][j-weight[i-1]]+val[i-1];
                        path[i][j] = 1;
                    }else{
                        f[i][j] = f[i-1][j];
                    }
                    //f[i][j] = Math.max(f[i-1][j], f[i-1][j-weight[i-1]]+val[i-1]);
                }
            }
        }
        for(int i=0;i<f.length;i++){
            for(int j=0;j<f[0].length;j++){
                System.out.print(f[i][j]+" ");
            }
            System.out.println();
        }

        int i=f.length-1;
        int j=f[0].length-1;
        while(i>0&&j>0){
            if(path[i][j] == 1){
                System.out.print("第"+i+"个物品装入 ");
                j -= weight[i-1];
            }
            i--;
        }

    }

}

一维数组(无需装满):

public class _01背包一维数组无需装满 {
    public static void main(String[] args) {
        //int[] weight = {3,5,2,6,4}; //物品重量
        //int[] val = {4,4,3,5,3}; //物品价值
        int[] w = {3,5,2,6,4};
        int[] v = {4,4,3,5,3};
        int maxw = 12;
        int[] f = new int[maxw+1];
        int i,j;
        for(i = 0; i < f.length; i++)
            f[i] = 0;
        for(i = 0; i < v.length; i++)
        {
            for(j = f.length - 1; j >= w[i]; j--)
            {
                //f[j] = f[j] > (f[j-w[i]] + v[i]) ? f[j] : (f[j-w[i]] + v[i]);
                f[j] = Math.max(f[j], f[j-w[i]] + v[i]);
            }
        }
        for(i = 0; i < f.length; i++)
            System.out.print(f[i] + " ");
        System.out.println();
    }

}

一维数组(装满):

public class _01背包需装满 {
    public static void main(String[] args) {
        int[] w = {3,5,2,6,4};
        int[] v = {4,4,3,5,3};
        int maxw = 3;
        int[] f = new int[maxw+1];
        int i,j;
        for(i = 1; i < f.length; i++)
            f[i] = Integer.MIN_VALUE;
        for(i = 0; i < v.length; i++)
            for(j = f.length - 1; j >= w[i]; j--)
                f[j] = f[j] > (f[j-w[i]] + v[i]) ? f[j] : (f[j-w[i]] + v[i]);
                //f[j] = Math.max(f[j], f[j-w[i]] + v[i]);

        for(i = 0; i < f.length; i++)
            System.out.print(f[i] + " ");
    }

}

注:装满和不装满主要区别是在与它们起始数组的初始化。无需装满初始化全为0,而需要装满的初始化f[0] = 0;其余各项1,2…n则置为Integer.MIN_VALUE,你可以这样理解,全部装满只有在一个物品重量为0时才能装入其它的则无需定义。

完全背包:
完全背包和01背包思想一样,只是先从物品重量开始计数,01背包是以从0开始计数,重量作为判断。

public class _完全背包 {
    public static void main(String[] args) {
        int[] w = {3,4,6,2,5};
        int[] v = {6,8,7,5,9};
        int maxw = 10;
        int[] f = new int[maxw+1];
        int i,j;
        for(i = 0; i < v.length; i++)
            for(j = w[i]; j <= f.length-1; j++)
                f[j] = f[j] > f[j-w[i]] + v[i] ? f[j] : f[j-w[i]] + v[i];
        for(i = 0; i < f.length; i++)
            System.out.print(f[i] + " ");
    }

}

以上纯属个人见解,如有错误求各位大佬不吝指教。

猜你喜欢

转载自blog.csdn.net/CogitoES_hw/article/details/81839735
今日推荐