动态规划0-1背包问题

动态规划总体的思想与分治法类似,也是将带求解的问题分解成若干个子问题。但是再使用动态规划的时候由于处理子问题比较多,而且这些子问题的数据在后面的操作中会使用到,因此在动态规划使用的时候还需要建立一个“表”。这个“表”就是一个数组,用于记录在处理每一分支的时候的数据。总体的思路还是将带求解的问题分解成若干个子问题  ,最后将这些子问题合并求得要求解的问题。

0-1 背包问题,指的是一个重量为W的背包,有着n个物品,这些物品的重量分别为wi(i<n),并且这些物品都有价值,分别为vi。要求如何装这些物品能够使得包中的物品的总价值最大。

用动态规划来处理这个问题时,则是将这个问题分解成如若干小问题:当背包质量为w时,放入前n个物品是取得最大的价值是多少?因此这个问题就从最基本的问题开始求:背包的质量为0,放入前0个物品,总价值最大为0。背包质量和物品个数依次增加,每一个物品在选择放入背包中都是只有两种状态:放入、不放。

设v[i,w]表示重量为w的背包中装入前i个物品的最大价值。vi表示第i个物品的价值,wi表示第i个物品的重量。

那么在整个过程中,对于每一个情况存在着三种情况:

(1)当i=0或者w等于0时,v[i,w]=0。当i=0,表示没有物品放入背包中,价值当然为0,同理背包重量为0,没有物品放入背包中,价值为0.

(2)当wi>w时,v[i,w]=v[i-1,w]。这个表示当第i个物品的重量大于w时,即这个物品没法放入背包中的,那么此时的价值为放入前i-1个物品的价值,因此v[i,w]=v[i-1,w]。注意:每一个v[i,w]既可以表示第i个物品放入背包中,也可以表示第i个物品没有放入背包中,只不过两种情况下的v[i,w]的值不同而已。

(3)当wi<=w&&i>0,v[i,w]=max{ v[i-1,w-wi]+vi , v[i-1,w] }。这表示当第i个物品可以放入背包中,那么比较放入包中的价值和没有放入包中的价值。放入包时:价值为v[i-1,w-wi]+vi,因为此时w代表加上了wi的值,因此要求没有放入第i个物品的价值求的是v[i-1,w-wi];没有放入包时:价值为v[i-1,w],这时w不包含wi,因此不需要减去wi。

因此求解该问题就是一次求解子问题,最后求出最大的价值。代码如下:

public class dongtaiguihua01 {

	public  static  void  main(String []args)
	{
		int W=17;		//背包的总重量
		int []w= {0,3,4,7,8,9};		//物品的相应重量
		int []v= {0,4,5,10,11,13};		//物品的相应价值
		int [][]value=new int [6][18];
		int []num= new int [5];
		for(int i=0;i<6;i++)
		{
			for(int j=0;j<18;j++)
			{
				if(i==0||j==0)
				{
					value[i][j]=0;   //第一种情况
				}
				else if(w[i]>j)
				{
					value[i][j]=value[i-1][j];		//第二种情况
				}
				
				else if(i>0&&w[i]<=j)		//第三种情况
				{
					int num1,num2;
					num1=value[i-1][j-w[i]]+v[i];		//放入后的价值
					num2=value[i-1][j];		//没有放入的价值
					if(num1>num2)
					{
						value[i][j]=num1;
						
					}
					else
					{
						value[i][j]=num2;
						
					}
				}
			}
		}
		
		//已经求出最大的价值,并且已经知道最后一个元素是否放入包中
		for(int i=4;i>=0;i--)
		{
			if(value[i+1][W]!=value[i][W])
			{
				num[i]=1;
				W=W-w[i+1];
			}
			else {
				num[i]=0;
			}
		}
		System.out.println("放入包中的物品为:");
		for(int i=0;i<5;i++)
		{
			if(num[i]==1)
			{
				System.out.println("质量为:"+w[i+1]+",价值为:"+v[i+1]);
			}
		}
		System.out.println("最大的价值为:"+value[5][17]);
	}
	
}

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值