PTA 背包问题凑零钱

题目大意
韩梅梅喜欢满宇宙到处逛街。现在她逛到了一家火星店里,发现这家店有个特别的规矩:你可以用任何星球的硬币付钱,但是绝不找零,当然也不能欠债。韩梅梅手边有 1 0 4 10^4 104 枚来自各个星球的硬币,需要请你帮她盘算一下,是否可能精确凑出要付的款额。
输入格式
输入第一行给出两个正整数: N ≤ 1 0 ​ 4 N≤10^{​4} N104​​ 是硬币的总个数, M ≤ 1 0 ​ 2 M ≤10^{​2} M102是韩梅梅要付的款额。第二行给出 N N N 枚硬币的正整数面值。数字间以空格分隔。
输出格式
在一行中输出硬币的面值 V ​ 1 ≤ V 2 ≤ ⋯ ≤ V k V_​1≤V_2 ≤⋯≤V_k V1V2Vk

### 解题思路 PTA韩梅梅零钱问题本质是一个典型的0 - 1背包问题变种。需要从给定的硬币集合中选择若干硬币,使得它们的面值之和恰好等于要付的款额。 可以使用动态规划的方法解决该问题,具体步骤如下: 1. 定义状态:设`dp[i][j]`表示前`i`个硬币能否凑出金额`j`,其值为布尔类型。同时,使用一个二维数组`choice`来记录每个硬币的选择情况。 2. 初始化:`dp[0][0]`为`True`,表示不选任何硬币可以凑出金额0;其余`dp[0][j]`为`False`。 3. 状态转移方程:对于第`i`个硬币,面值为`coins[i - 1]`,有两种情况: - 不选择第`i`个硬币:`dp[i][j] = dp[i - 1][j]`。 - 选择第`i`个硬币:当`j >= coins[i - 1]`时,`dp[i][j] = dp[i - 1][j - coins[i - 1]]`。 4. 最终结果:如果`dp[n][m]`为`True`,表示可以凑出金额`m`;否则不能。若能凑出,通过回溯`choice`数组找出具体的硬币组合。 ### 代码实现 ```python n, m = map(int, input().split()) coins = list(map(int, input().split())) coins.sort() # 按面值从小到大排序 # 初始化dp数组和choice数组 dp = [[False] * (m + 1) for _ in range(n + 1)] choice = [[False] * (m + 1) for _ in range(n + 1)] dp[0][0] = True # 动态规划过程 for i in range(1, n + 1): for j in range(m + 1): dp[i][j] = dp[i - 1][j] if j >= coins[i - 1] and dp[i - 1][j - coins[i - 1]]: dp[i][j] = True choice[i][j] = True # 判断是否能凑出金额m if not dp[n][m]: print("No Solution") else: # 回溯找出具体的硬币组合 result = [] j = m for i in range(n, 0, -1): if choice[i][j]: result.append(coins[i - 1]) j -= coins[i - 1] result.sort() print(" ".join(map(str, result))) ```
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符  | 博主筛选后可见
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

幸愉信奥

谢谢亲的支持,我会继续努力啦~

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值