111 lines
2.0 KiB
Go
111 lines
2.0 KiB
Go
package main
|
|
|
|
import (
|
|
"bufio"
|
|
"container/heap"
|
|
"fmt"
|
|
"log"
|
|
"os"
|
|
"strings"
|
|
)
|
|
|
|
func die(err error) {
|
|
log.Fatal(err)
|
|
}
|
|
|
|
func check(err error) {
|
|
if err != nil {
|
|
die(err)
|
|
}
|
|
}
|
|
|
|
func main() {
|
|
solve("sample")
|
|
solve("input")
|
|
}
|
|
|
|
func solve(filename string) {
|
|
input, err := os.Open(filename + ".x")
|
|
check(err)
|
|
|
|
scanner := bufio.NewScanner(input)
|
|
scanner.Split(bufio.ScanLines)
|
|
total := 0
|
|
for scanner.Scan() {
|
|
line := scanner.Text()
|
|
parts := strings.Fields(line)
|
|
var nums []uint32
|
|
for _, p := range parts {
|
|
var x uint32
|
|
fmt.Sscanf(p, "0x%x", &x)
|
|
nums = append(nums, x)
|
|
}
|
|
//fmt.Printf("%b %v\n", nums, parts)
|
|
n := best(nums[0], nums[1:])
|
|
fmt.Printf("%b %v\n", nums, n)
|
|
total += n
|
|
//fmt.Println(n)
|
|
}
|
|
check(scanner.Err())
|
|
fmt.Println(total)
|
|
|
|
}
|
|
|
|
// An CostHeap is a min-heap of ints.
|
|
type CostHeap struct {
|
|
heap []uint32
|
|
cost map[uint32]int
|
|
}
|
|
|
|
func (h *CostHeap) Len() int { return len(h.heap) }
|
|
func (h *CostHeap) Less(i, j int) bool { return h.cost[h.heap[i]] < h.cost[h.heap[j]] }
|
|
func (h *CostHeap) Swap(i, j int) { h.heap[i], h.heap[j] = h.heap[j], h.heap[i] }
|
|
|
|
func (h *CostHeap) Push(x any) {
|
|
// Push and Pop use pointer receivers because they modify the slice's length,
|
|
// not just its contents.
|
|
h.heap = append(h.heap, x.(uint32))
|
|
}
|
|
|
|
func (h *CostHeap) Pop() any {
|
|
old := h.heap
|
|
n := len(old)
|
|
x := old[n-1]
|
|
h.heap = old[0 : n-1]
|
|
return x
|
|
}
|
|
|
|
func best(target uint32, pool []uint32) int {
|
|
//var states = []uint32{}
|
|
var cost = make(map[uint32]int)
|
|
h := &CostHeap{nil, cost}
|
|
heap.Push(h, uint32(0))
|
|
for h.Len() > 0 {
|
|
s := heap.Pop(h).(uint32)
|
|
if s == target {
|
|
break
|
|
}
|
|
// enumerate all the states that can be reached by toggling button p
|
|
for _, p := range pool {
|
|
t := s ^ p
|
|
if cost_t, ok := cost[t]; ok {
|
|
if cost[s]+1 < cost_t {
|
|
cost[t] = cost[s] + 1
|
|
for i, x := range h.heap {
|
|
if x == t {
|
|
heap.Fix(h, i)
|
|
break
|
|
}
|
|
}
|
|
}
|
|
} else {
|
|
cost[t] = cost[s] + 1
|
|
//states = append(states, t)
|
|
heap.Push(h, t)
|
|
}
|
|
}
|
|
}
|
|
|
|
return cost[target]
|
|
}
|