逆向背包问题 洛谷P1802

逆向背包问题 洛谷P1802

看到这道题的时候我觉得大家一定会觉得这是一个很基础的背包模板题,但上手了之后感觉不太对劲,再读题就发现这个题的解题思路有点“逆"。
作为动态规划的新手,逆的背包也让我想了很久
下面先放出本题AC代码:

#include<bits/stdc++.h>
using namespace std;
int win[1005],lose[1005],use[1005]; 
long long v[1005][10000];
int main()
{
	int n,x;
	cin>>n>>x;
	for(int i=1;i<=n;i++)
	cin>>lose[i]>>win[i]>>use[i];
 for(int i=1;i<=n;i++)
	{
		for(int j=0;j<=x;j++)
		{		
			if(j>=use[i]&&v[i-1][j-use[i]]+win[i]>v[i-1][j]+lose[i])
			{
			v[i][j]=v[i-1][j-use[i]]+win[i];
		    }
			else v[i][j]=v[i-1][j]+lose[i];
		    
		}
	}
	cout<<v[n][x]*5<<endl;
	return 0;
 } 

我们先分析一波题目:
在这里插入图片描述
题目的意思用我的话来说就是:给你 x 钱,打败一个人花 use[i] 钱,无论打败与否都会给出一定的奖励,问在资金缺乏的情况下,如何选择打败对象使得奖励值最大。
现在将此题与传统背包问题做出对比:
解决传统背包问题的思路是:设背包的剩余容积为 x 求在这个剩余容积下的背包价值最大情况,所以我们需要遍历所有物品,每个物品考虑放与不放的价值。
现在把此题转化为背包问题来思考:此题应该要找 当你的敌人是第i个时, 还有j瓶药水的时候,奖励最大可能为多少,所以进行对比的参照物应该是 当你的敌人是第 i-1个时,还有j-use[i]瓶药水的时候,奖励最大值为多少。
这里很关键,仔细想想,为什么是j-use[i]瓶药水。
这样考虑,应为药水是用一点少一点的,那么我们做出的假设有两个,一个是:使用use[i]瓶药水打败这个敌人。另一个是:一瓶都不用,直接认输,将损失将到最小。
所以为了使假设一能够成立,我是不是要保证一定有足够的药水给我去打败这个敌人?
而我要找的是当我一共有 j 瓶药水时,我能得到的最大奖励。
所以如果又要实现假设一,又要满足这个前提,代码就要这样写:
1.为保证假设一 提前把use[i]提取出来 [j-use[i]]
2.为了找最大,就要找药水数为 j-use[i] 的最大,所以 v[i-1][j-use[i]]。
注意这一点后就是常规的比较了。


此题还有一点比较有趣,我第一次交WA了一半数据,看了数据后发现:打败一个敌人可以一瓶药水也不用,所以在写药水总共多少的时候应该从0开始,即如果一瓶药水也没有,也有可能打败一些敌人。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: 01背包是一个经典的动态规划问题,用于求解在限制物品体积或重量的情况下,能够获得的最大价值。 算法流程: 1. 定义状态:f[i][j] 表示前i个物品,体积不超过j的最大价值。 2. 状态转移:f[i][j] = max(f[i-1][j], f[i-1][j-v[i]]+w[i]),其中v[i]表示物品i的体积,w[i]表示物品i的价值。 3. 边界:f[0][j] = 0,0 <= j <= V,V为背包体积。 代码实现: ``` def knapsack(v, w, V): n = len(v) f = [[0 for j in range(V+1)] for i in range(n+1)] for i in range(1, n+1): for j in range(1, V+1): if j < v[i-1]: f[i][j] = f[i-1][j] else: f[i][j] = max(f[i-1][j], f[i-1][j-v[i-1]]+w[i-1]) return f[n][V] ``` 总结:01背包是一个典型的动态规划问题,通过定义状态,计算状态转移方程,以及初始化边界,即可解决该问题。 ### 回答2: 01背包问题是一个经典的动态规划问题,也是算法和编程中常见的考察点之一。给定一组物品,每个物品都有自己的重量和价值,在限定的背包容量下,选择一些物品放入背包中,使得背包中物品的总价值最大化。 解决01背包问题的常用方法是使用动态规划。我们可以定义一个二维数组dp,其中dp[i][j]表示在前i个物品中,背包容量为j的情况下,能够达到的最大价值。 基本思路是,对于每个物品i,我们可以有两种选择:放入背包或者不放入背包。如果我们选择将物品i放入背包中,那么背包的容量将减少weight[i],同时总价值将增加value[i];如果我们选择不放入物品i,那么背包的容量和总价值都不会发生变化。因此,我们可以通过比较这两种选择的结果,取较大的那个来更新dp[i][j]。 具体的动态规划转移方程如下: 1. 如果物品i的重量大于背包容量j,即weight[i] > j,那么dp[i][j] = dp[i-1][j],即不放入物品i,结果和前i-1个物品相同。 2. 如果物品i的重量小于等于背包容量j,即weight[i] <= j,有两种选择: a. 放入物品i:dp[i][j] = dp[i-1][j-weight[i]] + value[i] b. 不放入物品i:dp[i][j] = dp[i-1][j],结果和前i-1个物品相同。 3. 最终的结果为dp[n][c],即在前n个物品中,背包容量为c的情况下,所能达到的最大价值,其中n为物品的总个数,c为背包的容量。 通过动态规划的思想,我们可以逐步计算出dp数组的所有值,并找出最终的结果。该方法的时间复杂度为O(n*c),空间复杂度为O(n*c)。 在实际应用中,我们可以根据题目的具体要求进行相应的优化,如利用一维数组进行降维优化、使用滚动数组减少空间复杂度等。不同的优化方法可以根据具体情况灵活运用,以提高算法的效率。 ### 回答3: 01背包问题是一种经典的动态规划问题,它是指在一组不同重量和不同价值的物品中,选择一部分物品装入背包,使得背包中物品的总价值最大,同时不能超过背包的重量限制。 解决01背包问题的关键是构建一个二维数组dp,其中dp[i][j]表示在前i个物品中,背包容量为j时的最大价值。根据动态转移方程dp[i][j] = max(dp[i-1][j], dp[i-1][j-w[i]]+v[i]),可以逐步更新dp数组,最终得到dp[n][W]的最大价值。 具体的实现中,我们可以使用两层循环来更新dp数组。外层循环遍历物品,内层循环遍历背包容量,通过比较选择是否将当前物品放入背包。当物品的重量小于等于背包容量时,我们可以选择放入背包,此时背包中的总价值为dp[i-1][j-w[i]]+v[i];如果不放入背包,背包中的总价值为dp[i-1][j],取两者的较大值更新dp[i][j]。如果物品的重量大于背包容量,则不可能放入背包,即dp[i][j]保持不变。 最后,dp[n][W]即为所求的最大价值。可以通过反向遍历dp数组,根据dp[i][j]和dp[i-1][j]是否相等,判断物品i是否放入了背包,从而确定所选择的物品。 总之,通过动态规划的思想,我们可以解决01背包问题。这个问题有着广泛的应用,在资源分配、装箱、旅行路线规划等领域都有着重要的作用。 希望以上回答对您有所帮助!

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值