题目:给定正整数数组coins表示硬币的面额和一个目标总和t,请计算凑出总和t至少需要的硬币数目。每种硬币可以使用任意多枚。如果不能用输入的硬币凑出给定的总和,则返回-1。例如,如果硬币面额为[1,3,9,10],总额t为15,那么至少需要3枚硬币,即2枚面额为3的硬币及一枚面额为9的硬币。
分析:这个也是求总和的,不过每个元素可以取无限次,因此就是完全背包问题。可以使用一个矩阵来记录凑出总额最少需要多少个硬币。矩阵横轴为面额,纵轴为总和t。如下图所示,依次填充表格

设上述表格的名字为board,位置都从0开始数。
首先填充第一行,此时只有面额为1的硬币,如果要凑出总额1,则需要1枚硬币,所以board[0][0]=1,如果要凑出总额2,需要2枚硬币,因此board[0][1]=2,依次类推,把第一行填满了。
然后填充第二行,此时我们有面额为1的硬币,也有面额为3的硬币。
如果要凑出总额为1,因为3比1大,因此用硬币3是凑不出总额1的,因此board[1][0]使用board[0][0]的值。
凑出总额2时,也是一样的道理,board[1][1]=board[0][1].
当凑出总额3时,3//3 = 1,使用1枚硬币就可以了,这比用面额1使用3枚硬币要少,因此board[1][2]=1,代码里可以这样写board[i][j]=min( (j+1)//t[i], board[i-1][j])。
当凑出总额为4时,4//3=1,并且余1,应当使用1枚面额为3的,而对于余数而言,就要看上一行了,因为我们不能再使用3了,因此不能在面额3的这一行找答案,我们要看面额1的那一行里,总额为1时,需要几枚硬币。可以查表,看到board[0][0]等于1,因此如果使用面额为3和面额为1的硬币,凑出总额4需要1枚面额为3的,1枚面额为1的,总共需要2枚。比只使用面额1硬币的数量要少,因此board[1][3]=2,代码里可以这样写board[i][j] = min( (j+1)//t[i]+board[i-1][(j+1)%t[i]-1], board[i-1][j])
以此类推,将这个表格填完,最后一个board[3][14]就是此题的答案。
这里要注意一个东西,如果可选面额里第一个面额为2时,凑出总额1的硬币个数应该填多少呢?不能填0,原因如下:因为我们比较最小值,如果我们在此处填了0,那么当第二个可选面额为1时,就会出现如下情况:

当出现可选面额为1时,居然还是0个硬币。因为min(1//1, board[0][0])的结果为0. 因此可知,当凑不出总额时,不能填0,而应该填一个非常大的数,以保证凑不出的时候的情况的硬币数要大于能凑出总额的硬币数。在python里,我建议就填目标总额+1.即如果要凑出总额15,则当当前的硬币凑不出这个总额时,硬币数就填16,这样就能够保证正确性了。因此上面的表应该这样填:

实现代码如下:
t = [2,3,9,10]
target

博客介绍了如何使用动态规划解决完全背包问题,通过填充一个矩阵来记录达到目标总和所需的最少硬币数。详细分析了不同面额硬币组合的情况,并提供了Python代码示例。文章强调了初始化矩阵的重要性,特别是当无法凑出目标总和时,应填写一个较大的数值以确保正确性。
最低0.47元/天 解锁文章
2079

被折叠的 条评论
为什么被折叠?



