Day 14 solution
This one's part 1 destroyed me. I had a very difficult time, trying 3 separate approaches, each one of which worked for most cases but eventually fell apart on the 5th sample or my actual puzzle input. I ended up tweaking and rewriting until I landed on this which wasn't far off from what I was trying to do previously, but I had been overcomplicating things. Part 2 surprised me in that I expected a simple "ore available divided by ore needed for 1 fuel" would solve it, but of course the excess chemicals produced in any given reaction meant that it wasn't that simple. So this approach uses that estimate as a lower bound, since it always underestimates, and then bisects its way to the solution (starting at the lower bound and adding 1 each time took too long). I'm sure a smarter upper bound choice could lower the runtime of this by a bit, but runtime isn't bad enough right now for me to try any additional optimizations.
This commit is contained in:
26
utilities/bisect.go
Normal file
26
utilities/bisect.go
Normal file
@ -0,0 +1,26 @@
|
||||
package utilities
|
||||
|
||||
import (
|
||||
"math"
|
||||
)
|
||||
|
||||
// Bisect takes a known-good low and known-bad high value as the bounds
|
||||
// to bisect, and a function to test each value for success or failure.
|
||||
// If the function succeeds, the value is adjusted toward the maximum,
|
||||
// and if the function fails, the value is adjusted toward the minimum.
|
||||
// The final value is returned when the difference between the success
|
||||
// and the failure is less than or equal to the acceptance threshold
|
||||
// (usually 1, for integers).
|
||||
func Bisect[T Number](low, high, threshold T, tryFunc func(val T) bool) T {
|
||||
for T(math.Abs(float64(high-low))) > threshold {
|
||||
currVal := low + ((high - low) / 2)
|
||||
success := tryFunc(currVal)
|
||||
if success {
|
||||
low = currVal
|
||||
} else {
|
||||
high = currVal
|
||||
}
|
||||
}
|
||||
|
||||
return low
|
||||
}
|
@ -1,5 +1,7 @@
|
||||
package utilities
|
||||
|
||||
import "math"
|
||||
|
||||
func GCD[T Integer](a, b T) T {
|
||||
if b == 0 {
|
||||
return a
|
||||
@ -25,3 +27,23 @@ func LCM[T Integer](nums ...T) uint64 {
|
||||
func lcm[T Integer](a, b T) uint64 {
|
||||
return uint64(a*b) / uint64(GCD(a, b))
|
||||
}
|
||||
|
||||
func Min[T Number](nums ...T) T {
|
||||
numNums := len(nums)
|
||||
if numNums == 2 {
|
||||
return T(math.Min(float64(nums[0]), float64(nums[1])))
|
||||
}
|
||||
|
||||
if numNums == 0 {
|
||||
return 0
|
||||
}
|
||||
|
||||
least := nums[0]
|
||||
for i := 1; i < numNums; i++ {
|
||||
if nums[i] < least {
|
||||
least = nums[i]
|
||||
}
|
||||
}
|
||||
|
||||
return least
|
||||
}
|
||||
|
Reference in New Issue
Block a user