硬币找零之动态规划法|Go主题月

832 阅读1分钟

对于找零时使用最少的硬币,已经尝试过贪婪算法递归算法,下面将使用动态规划策略来解决最优化问题。

动态规划:用于寻找最优化问题,比如寻找最短路径。
在解决找零问题时,动态规划算法会从找零1分开始,然后系统地一直计算到所求解的硬币金额。这样做可以保证每一步都已经知道小于当前的找零金额所需的最少硬币数量。

以找零6分为例,我们把找零1到6分所需的最少硬币数量记录到以下表格:
找零.png

从 1 分开始,只需找 1 枚 1 分的硬币。
第 2 行展示了 1 分和 2 分所需的最少硬币数。同理,2 分只需找 2 枚 1 分的硬币。
第 5 行开始变得有趣起来,此时我们有 2 个可选方案:
要么找 5 枚 1 分的硬币, 要么找 1 枚 5 分的硬币。
哪个方案更好呢?
查表后发现,4 分所需的最少硬币数是 4,再加上 1 枚 1 分的硬币就得到 5 分(共需要 5 枚硬币); 如果直接找 1 枚 5 分的硬币,则最少硬币数是 1。
由于 1 比 5 小,因此我们把 1 存入表中。

使用Golang语言实现代码如下:

package main

import "fmt"

func minCoinsDynamicProgramming(coinValues []int, change int, minCoins []int, coinUsed []int) int {
	changes := make([]int, change+1)
	for i := 0; i <= change; i++ {
		changes[i] = i
	}
	fmt.Println("找零金额表:", changes)

	for _, cent := range changes {
		coinCount := cent
		newCoin := 1
		for _, coinValue := range coinValues {
			if coinValue <= cent {
				if minCoins[cent-coinValue]+1 < coinCount {
					coinCount = minCoins[cent-coinValue] + 1
					newCoin = coinValue
				}
			}
		}
		minCoins[cent] = coinCount
		coinUsed[cent] = newCoin
	}
	fmt.Println("找零最少硬币数量表:", minCoins)
	return minCoins[change]
}

func printCoins(coinUsed []int, change int) {
	coin := change
	for coin > 0 {
		thisCoin := coinUsed[coin]
		fmt.Println("找零硬币面值:", thisCoin)
		coin -= thisCoin
	}
}

func main() {
	coinValues := []int{1, 5, 10, 21, 25}
	change := 63
	minCoins := make([]int, change+1)
	coinUsed := make([]int, change+1)
	fmt.Println("最少硬币数量:", minCoinsDynamicProgramming(coinValues, change, minCoins, coinUsed))
	fmt.Println("找零面值表:", coinUsed)
	printCoins(coinUsed, change)
}