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) } } }