装箱问题 3

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/meiyongdesan/article/details/87901761

问题描述

设有n种物品,记作A1、A2、…、An,对应于每个Ai(1<=i<=n)都有一个重量Awi和价值Avi(重量和价值都为正整数)。另外,对应于每个Ai,都有一件可代替它的“代用品”Bi,Bi的重量和价值分别为Bwi和Bvi。

本题的任务是:选择这n件物品或其代用品的一个子集装进背包,使总重量不超过给定重量TOT,同时使总价值VAL最高。装填的第I步,要么装入Ai,要么装入Bi,要么Ai和Bi都不装。

输入描述

第一行:n TOT ,n<=100, TOT<=10000

第二行:AW1 A v1 B W1 Bv1

第三行:AW2 A v2 B W2 Bv2

……

第n+1行:AWn A vn B Wn Bvn

输出描述

只有一个数为最大的价值

样例输入

4 20

8 20 12 31

2 3 9 20

13 31 11 12

8 9 13 36

样例输出

40

问题分析

看到这种问题,第一反应使用动态规划。该问题和我之前的博客(装箱问题)特别相似,唯一不同在于本题中添加了代用品这个概念。因此在书写动态规划时,我们需要判断是否之前已经添加了原物品。我的做法是将原物品和代用品交替判断,这样只需要在判断代用品时不和上一列(包含原物品)进行比较即可。例如用a[max][n]表示最大重量为max时前n个物品的最大价值。那么当n为奇数时直接和n-1进行比较,但是当n为偶数时,就需要和n-2比较,跳过原物品那一列

源码

public static void main(String[] args)
{
	Scanner in = new Scanner(System.in);
	int n , max;
	n = in.nextInt();
	max = in.nextInt();
	int aPrice[] = new int[n+1];
	int aValue[] = new int[n+1];
	int bPrice[] = new int[n+1];
	int bValue[] = new int[n+1];
	for(int i=1;i<=n;i++)
	{
		aPrice[i] = in.nextInt();
		aValue[i] = in.nextInt();
		bPrice[i] = in.nextInt();
		bValue[i] = in.nextInt();
	}
	int a[][] = new int[max+1][2*n+1];
	for(int i=1;i<=2*n;i++)
	{
		// 原物品
		if(i%2 == 1)
			a[1][i] = 1>=aPrice[(i+1)/2]?aValue[(i+1)/2]:0;
		// 代用品
		else
			a[1][i] = 1>=bPrice[i/2]?bValue[i/2]:0;
	}
	for(int i=1;i<=max;i++)
	{
		a[i][1] = i>=aPrice[1]?aValue[1]:0;
	}
	for(int i=2;i<=max;i++)
	{
		for(int j=2;j<=2*n;j++)
		{
			a[i][j] = a[i-1][j]>a[i][j-1]?a[i-1][j]:a[i][j-1];
			// 使用原物品时只需要和上一列判断,即没有这个新的a物品时
			if(j%2 == 1)
			{
				if(i >= aPrice[(j+1)/2])
					a[i][j] = a[i-aPrice[(j+1)/2]][j-1]+aValue[(j+1)/2]>a[i][j]?a[i-aPrice[(j+1)/2]][j-1]+aValue[(j+1)/2]:a[i][j];
			}
			// 使用代用品时需要和上上一列判断,即上一个代用品出现的情况
			else
			{
				if(i >= bPrice[j/2])
					a[i][j] = a[i-bPrice[j/2]][j-2]+bValue[j/2]>a[i][j]?a[i-bPrice[j/2]][j-2]+bValue[j/2]:a[i][j];
			}
		}
	}
	System.out.println(a[max][2*n]);
}

测试结果

猜你喜欢

转载自blog.csdn.net/meiyongdesan/article/details/87901761