采药问题属于01背包问题

采用动态规划进行求解:

  • 保存结果:dp[i][j]表示前i件物品放入容量为j的背包,所能带来的最大价值
  • 递推公式:①如果第i件物品不放入背包,那么就代表我们要放的是前i - 1件物品 => dp[i][j] = dp[i - 1][j];②如果第i件物品放入背包,那么第i件物品的价值value[i]我已经获得了,除此以外,我还有j - weight[i]的空间可以放我们的前i - 1件物品;综上,可得递推公式为dp[i][j] = max(dp[i - 1][j], dp[i - 1][j - weight[i]] + value[i]
  • 空间优化:注意到上面的递推公式中,dp[i - 1]是固定不动的,因此优化成dp[j] = max(dp[j], dp[j - weight[i]] + value[i])
  • 注意:因为j - weight[i]小于j,为了避免在访问dp[j]之前,dp[j - weight[i]]已被修改,我们需要倒序遍历
  • 最终解为:dp[m](m为背包总容量,下标范围我们设置为[0, m]
def medicineCollection():
    while True:
        try:
            list = [int(i) for i in input().split()]
            # m为背包容量(这里是采药时间),n为物品数量(这里是草药数目)
            m, n = list[0], list[1]
            # weight为物品对应的重量(这里是采摘草药所需时间),value为物品对应的价值(这里是草药的价值)
            weight, value = [], []
            for i in range(n):
                list = [int(j) for j in input().split()]
                weight.append(list[0])
                value.append(list[1])
            dp = [0 for i in range(m + 1)]  # 设置dp范围为[0, m]
            for i in range(n):
                for j in range(m, weight[i] - 1, -1): # 逆序遍历的范围为[m, weight[i]]
                    dp[j] = max(dp[j], dp[j - weight[i]] + value[i])
            print(dp[m])
        except (EOFError, KeyboardInterrupt):
            break
            
if __name__ == '__main__':
    medicineCollection()