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

来源:互联网 发布:嵌入式底层软件开发 编辑:程序博客网 时间:2024/05/21 06:19

一、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();    }}
1 0
原创粉丝点击