计蒜客——草药的价值——背包问题

辰辰是个天资聪颖的孩子,他的梦想是成为世界上最伟大的医师。为此,他想拜附近最有威望的医师为师。医师为了判断他的资质,给他出了一个难题。医师把他带到一个到处都是草药的山洞里对他说:“孩子,这个山洞里有一些不同的草药,采每一株都需要一些时间,每一株也有它自身的价值。我会给你一段时间,在这段时间里,你可以采到一些草药。如果你是一个聪明的孩子,你应该可以让采到的草药的总价值最大。”  如果你是辰辰,你能完成这个任务吗?

输入文件medic.in的第一行有两个整数T(1  < =  T  < =  1000)和M(1  < =  M  < =  100),用一个空格隔开,T代表总共能够用来采药的时间,M代表山洞里的草药的数目。接下来的M行每行包括两个在1到100之间(包括1和100)的整数,分别表示采摘某株草药的时间和这株草药的价值。

输出文件medic.out包括一行,这一行只包含一个整数,表示在规定的时间内,可以采到的草药的最大总价值。

对于30%的数据,M  < =  10;对于全部的数据,M  < =  100。

样例输入
<think>这是一个经典的动态规划问题——0-1背包问题。在这个问题中,我们有T的总时间(背包容量),M株草药(物品),每株草药有采摘时间(重量)和价值。目标:在不超过总时间T的前提下,使得采到草药总价值最大。我们将使用动态规划来解决。定义dp[i][j]表示面对前i株草药,在时间j内可以获得的最大价值。状态转移方程:对于第i株草药(时间t_i,价值v_i),我们可以选择采或者不采。不采:dp[i][j]=dp[i-1][j]采:如果j>=t_i,则dp[i][j]=dp[i-1][j-t_i]+v_i因此:dp[i][j]=max(dp[i-1][j],dp[i-1][j-t_i]+v_i)(当j>=t_i)由于M最大为100,T最大为1000,我们可以使用二维数组,但也可以优化为一维数组(滚动数组)。这里我们使用一维数组优化,即使用dp[j]表示时间j内的最大价值。注意:内层循环需要从大到小遍历,以避免覆盖之前的状态。步骤:1.初始化dp数组,长度为T+1,全部为0。2.依次考虑每一株草药(从1到M),对于当前草药(时间t,价值v),从时间T开始倒序遍历到t(因为当时间小于t时,无法采这株草药):dp[j]=max(dp[j],dp[j-t]+v)3.dp[T]即为答案(注意:实际上最大价值可能出现在小于T的时间,所以实际上我们遍历过程中最大值在dp数组中,但最后dp[T]不一定是最大值,我们需要整个数组的最大值?)但是注意,我们的背包不一定需要装满,但题目要求总时间不超过T即可,所以最大值可能是dp[0..T]中的最大值?但动态规划过程中,我们求的是在不超过j时间的情况下的最大价值,所以dp[T]就是不超过T时间的最大价值。而且我们倒序遍历时,dp[T]就是考虑了所有草药后,在时间T内的最大价值。实际上,由于我们不需要恰好装满,所以dp数组是单调不减的,因此dp[T]就是所有时间不超过T的最大价值。但是根据0-1背包的标准解法,我们最后的结果就是dp[T](注意:我们这里的一维dp数组在循环结束后,dp[j]表示在总时间不超过j的情况下的最大价值)。所以答案就是dp[T]。然而,我们看用例:输入:T=70,M=3草药1:71100->因为71>70,所以无法采草药2:691草药3:12根据我们的方法,当我们考虑草药2时(69,1),只有j>=69时,dp[j]可以更新为max(dp[j],dp[j-69]+1);然后考虑草药3(1,2),对于j>=1,dp[j]更新为max(dp[j],dp[j-1]+2)。我们初始化dp数组全0。草药2:对于j=69..70,dp[j]=max(0,dp[j-69]+1)=1(因为j-69>=0,而dp[j-69]在初始时为0,所以dp[69]和dp[70]都变为1)草药3:对于j=70:dp[70]=max(dp[70]=1,dp[69]+2=1+2=3)->3j=69:dp[69]=max(dp[69]=1,dp[68]+2=0+2=2)->2j=68~1:同理更新为0->2(但是因为我们只要求到T=70,所以不用管更小的)最后dp[70]=3,符合用例输出。因此,我们的方法是正确的。代码步骤:读取T和M初始化一个长度为T+1的数组dp,全部为0循环M次,每次读取一株草药的时间和价值倒序遍历j从T到当前草药的时间,更新dp[j]输出dp[T]注意:因为题目中每株草药只能采一次,所以我们倒序遍历时间。我们使用Python实现。</think> 这是一个经典的0-1背包问题,其中T表示背包容量(总时间),M表示物品数量(草药数量),每株草药的采摘时间是物品重量,价值是物品价值。目标是最大化在不超过总时间T的情况下采集的草药总价值。 ### 解决方案 我们使用动态规划来解决这个问题,核心是维护一个一维数组`dp`,其中`dp[j]`表示在时间j内能获得的最大价值。通过倒序更新数组避免状态覆盖。 ```python T, M = map(int, input().split()) # 初始化dp数组,长度为T+1,所有值为0 dp = [0] * (T + 1) for _ in range(M): t, v = map(int, input().split()) # 倒序遍历时间:从T到当前草药所需时间t for j in range(T, t - 1, -1): if dp[j] < dp[j - t] + v: dp[j] = dp[j - t] + v print(dp[T]) ``` ### 代码解释 1. **输入处理**:先读取总时间T和草药数量M 2. **初始化dp数组**:创建长度为T+1的数组,初始值全0 3. **遍历每株草药**: - 对于每株草药,读取其时间t和价值v - 使用倒序循环从T到t更新dp数组: - `dp[j] = max(dp[j], dp[j - t] + v)` 比较不采与采当前草药的收益 4. **输出结果**:`dp[T]`即表示在T时间内能获得的最大价值 ### 算法复杂度 - 时间复杂度:O(M×T),需要遍历所有草药及所有可能的时间 - 空间复杂度:O(T),仅需一维数组存储状态 ### 示例分析 对于输入: ``` 70 3 71 100 69 1 1 2 ``` - 第一株草药(71,100)超时跳过 - 第二株草药(69,1):使时间69-70的价值变为1 - 第三株草药(1,2):更新dp[70]=max(1, dp[69]+2)=max(1,0+2)=3 最终输出3,匹配用例。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值