01背包实战 - 最小邮票数

  • 题目要求:给定不同面额的邮票,要求我们用最少的邮票数,达到指定的面值
  • 求解思路:该题属于典型的01背包问题,因为给定邮票张数时,相同面额也认为是单独的一张,即只有0(不拿)和1(拿)两种状态 指定面值为我们的背包容量m,给定的邮票张数为我们的物品数量n,每张邮票的价值我们认为是相同的,需要注意的是,这里要求的是最小,而不是最大,因此 需要对递推公式进行修改,这里我们直接采用空间优化后的方法
  • 递推公式:dp[j] = min(dp[j], dp[j - weight[i]] + value[i]
  • 难点分析:①无解的判断:将dp数组初始化为无穷大,若最后dp[m]为无穷大,则说明无解,输出0即可,反之,输出dp[m]; ②确保背包完全放满:添加一条判断,if j == weight[i]: dp[j] = 1,其余情况再进行递推
def minStamps():
    while True:
        try:
            # m为背包容量(这里是指定的面值),n为物品数量(这里是给定的邮票张数)
            m, n = int(input()), int(input())
            # weight为物品对应的重量(这里是邮票的面值),value为物品对应的价值(这里是相同的,设为1)
            weight = [int(i) for i in input().split()]
            value = [1 for i in range(n)]
            inf = float('inf')
            dp = [inf for i in range(m + 1)]
            for i in range(n):
                for j in range(m, weight[i] - 1, -1):
                    if j == weight[i]:
                        dp[j] = 1
                    else:
                        dp[j] = min(dp[j], dp[j - weight[i]] + value[i])
            # dp[m]为无穷大,即无解
            if dp[m] == inf:
                print(0)
            else:
                print(dp[m])
        except (EOFError, KeyboardInterrupt):
            break


if __name__ == '__main__':
    minStamps()