algo/go/41_dynamic_programming/backtracking/leastcoins.go
Shang, Rocky 477f78510b add 41_dp
2019-06-23 10:17:13 +08:00

103 lines
2.2 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

package backtracking
import (
"fmt"
)
const intMax = int(^uint(0) >> 1)
var Cnt int
// LeastCoins find least number of coins of which the total values are equals a given one
func LeastCoins(targetTotal int, coinOptions []int) int {
minNum := intMax
memo := make([][]int, targetTotal+1)
for i := range memo {
memo[i] = make([]int, len(coinOptions))
}
fmt.Println("start")
leastCoins(&minNum, 0, targetTotal, len(coinOptions)-1, coinOptions, memo)
fmt.Println("end")
return minNum
}
func leastCoins(minNum *int, cNum, totalValue, opIndex int, coinOptions []int, memo [][]int) {
Cnt++
if 0 == totalValue {
if cNum < *minNum {
*minNum = cNum
}
return
}
if opIndex < 0 {
return
}
num4Option := 0
remaining := totalValue - coinOptions[opIndex]*num4Option
for remaining >= 0 {
if opIndex != 0 {
if shouldSkip(memo, remaining, opIndex-1, cNum+num4Option) {
goto Next
}
}
leastCoins(minNum, cNum+num4Option, remaining, opIndex-1, coinOptions, memo)
Next:
num4Option++
remaining = totalValue - coinOptions[opIndex]*num4Option
}
}
func shouldSkip(memo [][]int, totalValue, nextOpIdex, cNum int) bool {
if memo[totalValue][nextOpIdex] > 0 && memo[totalValue][nextOpIdex] <= cNum {
fmt.Printf("skip%d, %d as %d <= %d \n", totalValue, nextOpIdex, memo[totalValue][nextOpIdex], cNum)
return true
}
if memo[totalValue][nextOpIdex] == 0 || memo[totalValue][nextOpIdex] > cNum {
memo[totalValue][nextOpIdex] = cNum
}
return false
}
func LeastCoins2(targetTotal int, coinOptions []int) int {
minNum := intMax
memo := make([][]bool, targetTotal)
for i := range memo {
memo[i] = make([]bool, targetTotal/coinOptions[0])
}
fmt.Println("start")
leastCoins2(&minNum, targetTotal, coinOptions, 0, 0, memo)
fmt.Println("end")
return minNum
}
func leastCoins2(minNum *int, targetTotal int, coinOptions []int, cNum, cValue int, memo [][]bool) {
Cnt++
if cValue == targetTotal {
if *minNum > cNum {
*minNum = cNum
}
return
}
for _, coin := range coinOptions {
if coin+cValue <= targetTotal && !memo[cValue+coin-1][cNum] {
memo[cValue+coin-1][cNum] = true
leastCoins2(minNum, targetTotal, coinOptions, cNum+1, cValue+coin, memo)
}
}
}