JAVA动态规划(五)--01背包问题及装箱问题

一、01背包问题:
问题:01背包是在M件物品取出若干件放在空间为W的背包里,每件物品的体积为W1,W2……Wn,与之相对应的价值为P1,P2……Pn。在给定容量为C的条件下,求如何选取物体使带来的价值最大化。

在选择物品的时候,对每种物品i只有两种选择,即装入背包或不装入背包。不能讲物品i装入多次,也不能只装入物品的一部分。因此,该问题被称为0-1背包问题。

问题分析:令f(i,j)表示在前i(1<=i<=n)个物品中能够装入容量为j(1<=j<=C)的背包中的物品的最大价值,则可以得到如下的动态规划函数:
(1)V(i,0)=V(0,j)=0
(2)f(i,j)=f(i-1,j) j< wi ;
f(i,j)=max{f(i-1,j) ,f(i-1,j-wi)+vi) } j>wi

(1)式表明:如果第i个物品的重量大于背包的容量,则装人前i个物品得到的最大价值和装入前i-1个物品得到的最大价是相同的,即物品i不能装入背包;第(2)个式子表明:如果第i个物品的重量小于背包的容量,则会有一下两种情况:(a)如果把第i个物品装入背包,则背包物品的价值等于第i-1个物品装入容量位j-wi 的背包中的价值加上第i个物品的价值vi; (b)如果第i个物品没有装入背包,则背包中物品价值就等于把前i-1个物品装入容量为j的背包中所取得的价值。显然,取二者中价值最大的作为把前i个物品装入容量为j的背包中的最优解。

java代码如下:

package dynamic_programming;

import java.util.Scanner;

/** * @author Gavenyeah * * @date Time: 2016年4月22日下午5:41:02 */
//01背包问题,M件物品的重量不同,带来的价值不同,在给定最大重量容量下,找出能带来最大价值的组合
//状态转移方程: f(i,j)=max{f(i-1,j-wi)+vi, f(i-1,j)}
public class Package_0_1 {
    int weight[]=null;
    int value[] = null;
    int C = 0;
    int m=0;

    public static void main(String[] args) {
        Package_0_1 p01 = new Package_0_1();
        p01.getInput();
        System.out.println(p01.getValue());

    }
    public int getValue(){
        int[][] maxValue=new int [m+1][C+1];//m和C的值加1的目的是避免单独处理i-0和j=0的情况
        for(int i = 1; i < m+1; i++){
            for(int j = 1; j < C + 1; j++){
                if(j>=weight[i])
                    //根据状态转移方程计算当前最大价值
                    maxValue[i][j] = Math.max(maxValue[i-1][j-weight[i]]+value[i],maxValue[i-1][j]);
                else maxValue[i][j] = maxValue[i-1][j];
            }
        }
        return maxValue[m][C];//返回m个物体,容量为C时的最大价值
    }

    public void getInput() {//从键盘输入数据
        Scanner cin = new Scanner(System.in);
        System.out.print("背包最大容量:");
        C = cin.nextInt();
        System.out.print("请输入物品数:");
        m = cin.nextInt();
        weight = new int[m+1];
        System.out.print("依次输入每件物品的重量:");
        for (int i = 1; i < m+1; i++) {
            weight[i] = cin.nextInt();
        }
        System.out.print("依次输入每件物品的价值:");
        value = new int[m+1];
        for (int i = 1; i < m+1; i++) {
            value[i] = cin.nextInt();
        }
        cin.close();
    }
}

二、装箱问题(一维):

问题: 装箱问题:有一个箱子容量为v(正整数,o≤v≤20000),同时有n个物品(o≤n≤30),每个物品有一个体积(正整数)。要求从m个物品中,任取若千个装入箱内,使箱子的剩余空间为最小。

分析:装箱问题与01背包问题差不多,状态转移方程也差不多。
f(i,j)表示前i件物品在给定j体积时所能达到的最大值。
f(i, j)=max(f(i-1,j) , f(i-1, j-vi)+vi)

代码:

package dynamic_programming;

import java.util.Scanner;

/** * @author Gavenyeah * @date Time: 2016年4月23日下午10:40:35 * @des: */
// 装箱问题:有一个箱子容量为v(正整数,o≤v≤20000),同时有n个物品(o≤n≤30),每个物品有一个体积
// (正整数)。要求从m个物品中,任取若千个装入箱内,使箱子的剩余空间为最小。
public class BinPacking {
    int volume[] = null;
    int max_V = 0;

    public static void main(String[] args) {
        BinPacking bp = new BinPacking();
        bp.getInput();
        bp.binPacking();
    }

    // f(i,j)表示前i件物品在给定j体积时所能达到的最大值
    public void binPacking() {
        int[][] maxSumVolume = new int[volume.length][max_V + 1];
        for (int i = 1; i < volume.length; i++) {
            for (int j = 1; j <= max_V; j++) {
                if (j >= volume[i]) {
                    maxSumVolume[i][j] = Math.max(maxSumVolume[i - 1][j],
                            maxSumVolume[i - 1][j - volume[i]] + volume[i]);
                }
            }
        }
        int minSurplus = max_V - maxSumVolume[volume.length - 1][max_V];
        System.out.println("最小剩余:" + minSurplus);
    }

    public void getInput() {// 从键盘输入数据
        Scanner cin = new Scanner(System.in);
        System.out.print("请输入箱子容量:");
        max_V = cin.nextInt();
        System.out.print("请输入物品数:");
        int m = cin.nextInt();
        volume = new int[m + 1];
        System.out.print("依次输入每件物品的重量:");
        for (int i = 1; i < m + 1; i++) {
            volume[i] = cin.nextInt();
        }
        cin.close();
    }
}
    原文作者:动态规划
    原文地址: https://blog.csdn.net/y999666/article/details/51223607
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞