关于带限制条件的二维装箱-------重量价值双重限制下,使得价值最大

在做题的时候,遇到一个 二维背包问题,需要在重量不超过重量限制的情况下,使价值接近价值限制,但不能超过它。经过尝试后发现,对G矩阵进行一些处理可以得出结果。

首先是从value[] 中选出一个不超过,但最接近valueLimit的值,记录它的位置,然后去G矩阵里从这个位置开始倒推,可以得到想要的解,即物品的位置。代码如下:

iimport java.util.Arrays;
import java.util.Scanner;

public class Knapsack {
    private final static int MIN = Integer.MIN_VALUE;
    public static void main(String[] args){
    	int wLimit = 8;
    	int vLimit = 13;
    	int[] w = {1,2,2,4,6};
        int[] v = {2,3,5,6,7};
        knapsackOptimal(wLimit, w,vLimit, v);
    }
    /**
     * @param weightLimit  总重量限制    
     * @param weight 物品重量
     * @param valueLimit   总价值限制
     * @param value  物品价值
     * 在总重量,和总价值不超出限制条件下,使得价值最大化
     */
    public static void knapsackOptimal(int weightLimit, int[] weight, int valueLimit,int[] value) {
        int n = weight.length; 
        int[] w = new int[n + 1];
        int[] v = new int[n + 1];
        //G[i][j]表示前i个物品能装入容量为j的背包中的最大价值
        int[][] G = new int[n + 1][weightLimit + 1];
        for (int i = 1; i < n + 1; i++) {
            w[i] = weight[i - 1];
            v[i] = value[i - 1];
        }
        //初始化values[0...c]=0————在不超过背包容量的情况下,最多能获得多少价值
        //原因:如果背包并非必须被装满,那么任何容量的背包都有一个合法解“什么都不装”,这个解的价值为0,所以初始时状态的值也就全部为0了
        int[] values = new int[weightLimit + 1];
        //初始化values[0]=0,其它全为负无穷————解决在恰好装满背包的情况下,最多能获得多少价值的问题
        //原因:只有容量为0的背包可以什么物品都不装就能装满,此时价值为0,其它容量背包均无合法的解,属于未定义的状态,应该被赋值为负无穷
        /*for (int i = 1; i < values.length; i++) {
            values[i] = MIN;
        }*/
        for (int i = 1; i < n + 1; i++) {
            for (int t = weightLimit; t >= w[i]; t--) {
                if ( (values[t] < values[t - w[i]] + v[i] ) ) {
                	 values[t] = values[t - w[i]] + v[i];
                     G[i][t] = 1;
                }
            }      
        }
        System.out.println("价值矩阵:"+Arrays.toString(values));
        System.out.println("无价值限制下的最大价值:" + values[weightLimit]);
        System.out.println("G矩阵: ");
        for(int i=0;i<G.length;i++){
        	System.out.println(Arrays.toString(G[i]));
        }
        
        int index = getValueIndex(values,valueLimit);
        
        System.out.println("满足价值限制条件下的最大价值:"+values[index]);
        System.out.println("index"+index);     
        /*
                    输出顺序:逆序输出物品编号
      	注意:这里另外开辟数组G[i][v],标记上一个状态的位置
        G[i][v] = 1:表示物品i放入背包了,上一状态为G[i - 1][v - w[i]]
  		G[i][v] = 0:表示物品i没有放入背包,上一状态为G[i - 1][v]
        */
        System.out.println("输出物品位置: ");
        int i = n;
//        int j = weightLimit;//无限制下计算位置,从最后一列开始倒推
        int j = index;//有限制下计算物品位置,从该行开始倒推
        while (i > 0) {
            if (G[i][j] == 1) {
                System.out.print(i + " ");
                j -= w[i];
            }
            i--;
        }
    }
    //Finds the position of the value in the largest value array ( value[] )that 
    //is less than and closest to valueLimit .
	private static int getValueIndex(int[] values,int valueLimit) {
		int index = 0;
		// TODO Auto-generated method stub
		if(valueLimit-values[values.length-1]>0){
        	index = values.length-1;
        }else{
        	for(int i=0;i<values.length;i++){
    	     	if(valueLimit-values[i]<0){
    	     		index = i-1;
    	     		break;	     		
    	     	}if(valueLimit-values[i]==0){
    	     		index = i;
    	     		break;	
    	     	}	    	     	
    	    }
        }
		return index;
	}
}

样例运行结果

价值矩阵:[0, 2, 5, 7, 8, 10, 11, 13, 14]
无价值限制下的最大价值:14
G矩阵: 
[0, 0, 0, 0, 0, 0, 0, 0, 0]
[0, 1, 1, 1, 1, 1, 1, 1, 1]
[0, 0, 1, 1, 1, 1, 1, 1, 1]
[0, 0, 1, 1, 1, 1, 1, 1, 1]
[0, 0, 0, 0, 0, 0, 1, 1, 1]
[0, 0, 0, 0, 0, 0, 0, 0, 0]
满足价值限制条件下的最大价值:13
index7
输出物品位置: 
4 3 1 

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值