110 lines
2.4 KiB
Go
110 lines
2.4 KiB
Go
package main
|
|
|
|
import (
|
|
"fmt"
|
|
"sort"
|
|
)
|
|
|
|
const (
|
|
INFINITY = 26
|
|
)
|
|
|
|
var debugSearch bool
|
|
|
|
type DummyWriter struct {
|
|
}
|
|
|
|
func (d DummyWriter) Write(p []byte) (n int, err error) {
|
|
n = len(p)
|
|
return
|
|
}
|
|
|
|
func DebugSearch(input []rune) {
|
|
debugSearch = true
|
|
parsed := NewParser(input).Parse()
|
|
generator := NewStdGenerator(DummyWriter{})
|
|
generator.Generate(parsed)
|
|
}
|
|
|
|
func SearchPlates(plates map[float64]int, goalWeight float64) []float64 {
|
|
if debugSearch {
|
|
fmt.Println("searching", goalWeight)
|
|
}
|
|
root := &DFSNode{}
|
|
root.remainingWeight = goalWeight
|
|
root.residualPlates = make(map[float64]int)
|
|
root.plate = -1
|
|
for k, v := range plates {
|
|
root.residualPlates[k] = v
|
|
}
|
|
optimum := root
|
|
root.search(&optimum)
|
|
usedPlates := optimum.usedPlates()
|
|
if debugSearch {
|
|
fmt.Println("found", usedPlates)
|
|
}
|
|
return usedPlates
|
|
}
|
|
|
|
type DFSNode struct {
|
|
parent *DFSNode
|
|
depth int
|
|
remainingWeight float64
|
|
plate float64
|
|
residualPlates map[float64]int
|
|
}
|
|
|
|
func (parent *DFSNode) newChild(plate float64) *DFSNode {
|
|
node := &DFSNode{}
|
|
node.parent = parent
|
|
node.depth = parent.depth + 1
|
|
node.remainingWeight = parent.remainingWeight - plate*2
|
|
node.plate = plate
|
|
node.residualPlates = make(map[float64]int)
|
|
for k, v := range parent.residualPlates {
|
|
node.residualPlates[k] = v
|
|
}
|
|
node.residualPlates[plate] -= 2
|
|
return node
|
|
}
|
|
|
|
func (n *DFSNode) usedPlates() (plates []float64) {
|
|
for node := n; node != nil; node = node.parent {
|
|
if node.plate > 0 {
|
|
plates = append([]float64{node.plate}, plates...)
|
|
}
|
|
}
|
|
return
|
|
}
|
|
|
|
func (n *DFSNode) successors() (children []*DFSNode) {
|
|
keys := []float64{}
|
|
for weight, amount := range n.residualPlates {
|
|
if amount >= 2 && weight*2 <= n.remainingWeight && (n.plate == -1 || weight <= n.plate) && n.remainingWeight/weight <= INFINITY {
|
|
keys = append(keys, weight)
|
|
}
|
|
}
|
|
sort.Float64s(keys)
|
|
for i := len(keys) - 1; i >= 0; i-- {
|
|
children = append(children, n.newChild(keys[i]))
|
|
}
|
|
return
|
|
}
|
|
|
|
func (n *DFSNode) search(optimum **DFSNode) {
|
|
successors := n.successors()
|
|
if len(successors) == 0 {
|
|
// leaf
|
|
if n.remainingWeight < (*optimum).remainingWeight || (n.remainingWeight == (*optimum).remainingWeight && n.depth < (*optimum).depth) {
|
|
*optimum = n
|
|
if debugSearch {
|
|
fmt.Printf("optimum: residual plates %v, remaining weight %v\n", (*optimum).residualPlates, (*optimum).remainingWeight)
|
|
}
|
|
}
|
|
} else {
|
|
for _, succ := range successors {
|
|
succ.search(optimum)
|
|
}
|
|
}
|
|
}
|