背包第三篇,完全背包问题详解

本次要讲的是完全背包问题的详解:他和01背包有很多相同之处;
可以参考我之前的01背包,然后就能更好的理解这个了。

首先介绍问题,现有物品a,b,c三样,价格分别为{1,4,3};质量分别为{1,3,2},现在求一个背包容量为n的背包怎么装物品的价值为最大;商品数量为无限,01背包问题和完全背包问题的差别就在于01只能放1次,完全背包可以放多次。
那么我们似乎就可以得到他的算法

int dp[背包容量+1];//背包最大价值
int v[],w[];//物品质量、物品价值
for(int i=0;i<物品种类;i++)
{
	for(int j=v[i];k<=背包总容量;j++)
	{
		dp[j]=max(dp[j],dp[j-v[i]]+w[i]);
	}
}

其中状态转移方程为f[m]=max(f[m],f[m-v [ i ] ]+w[i] ),看着好像有点难以理解,不妨我们来证明一下为什么会得到这个;
首先说一下为什么式从小到大递增,如果从大到小,你是无法把所有的情况都考虑进去的,你当前所获取k*v[i]的在你之前的子问题里没有解。然而从小到大枚举,会逐层递增上去,可以遍历所有的情况。
然后我们证明一下这个状态转移方程,为什么正确,假设当某时刻的 j 里,必然包含着k个v[i],

f[ j ]= f[ j - kv[i] ]+kw[i]

那么他必然是由

f[j-(k-1)*v[i]]+(k-1)*w[i]

转移过来的,
然后依次转移他们的值其实来自于

f[j-v[i]]+w[i]

那么f[j-v[i]]+w[i]必然可以由于i值的变化递推到f[ j - k* v[i] ]+k*w[i];
动态规划思路就是由子问题传递,然后通过上层的子问题所得的最优解一步一步推到整个父问题的最优解。

下面贴上我java的代码

public static void main(String[] args) {
        int[] v={1,3,3};//价格
        int[] w={1,4,2};//重量
        int n=3;//背包容量
        int[] bag=new int[n+1];

        for(int i=0;i<v.length;i++)
        {
            for(int j=w[i];j<=n;j++)
            {
                bag[j]=Math.max(bag[j],bag[j-w[i]]+v[i]);
            }

        }

        System.out.println(bag[n]);
    }

介绍完了问题我们不妨做个简单的问题练练手,来自leetcode的动态规划算法题
给定数量不限的硬币,币值为25分、10分、5分和1分,编写代码计算n分有几种表示法。(结果可能会很大,你需要将结果模上1000000007)

就不做详细分析了典型的动态规划完全背包类问题;

int query(int n)
{
	int[] coins={1,5,10,25};
	int[] dp=new int[n+1];
	dp[0]=1;
	for(int coin:coins){
		for(int i=coin;i<=n;i++)
		{	
			dp[i]=(dp[i]+dp[i-coin])%1000000007;
		}
	}
	return dp[n];
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值