2025-12-10 07:21:28 +00:00

154 lines
2.9 KiB
Go

package main
import (
"bufio"
"fmt"
"log"
"os"
"strconv"
"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)
check(err)
scanner := bufio.NewScanner(input)
scanner.Split(bufio.ScanLines)
total := 0
for scanner.Scan() {
line := scanner.Text()
parts := strings.Fields(line)
parts = parts[1:]
var jolts []Jolts
for _, p := range parts {
j, err := parseJolt(p)
check(err)
jolts = append(jolts, j)
}
fmt.Printf("%v %v\n", jolts, parts)
n := best(jolts[len(jolts)-1], jolts[:len(jolts)-1])
fmt.Printf("%s = %v\n", line, n)
total += n
//fmt.Println(n)
}
check(scanner.Err())
fmt.Println(total)
}
type Jolts [10]int16
func parseJolt(s string) (Jolts, error) {
if s[0] == '(' {
return parseJoltByIndex(s)
} else if s[0] == '{' {
return parseJoltByValue(s)
}
return Jolts{}, fmt.Errorf("invalid jolts: %q", s)
}
func parseJoltByIndex(s string) (Jolts, error) {
var j Jolts
s = strings.Trim(s, "()")
for _, part := range strings.Split(s, ",") {
idx, err := strconv.ParseInt(part, 10, 16)
if err != nil {
return j, err
}
j[idx] = 1
}
return j, nil
}
func parseJoltByValue(s string) (Jolts, error) {
var j Jolts
s = strings.Trim(s, "{}")
for i, part := range strings.Split(s, ",") {
val, err := strconv.ParseInt(part, 10, 16)
if err != nil {
return j, err
}
j[i] = int16(val)
}
return j, nil
}
// An CostHeap is a min-heap of ints.
type CostHeap struct {
heap []Jolts
cost map[Jolts]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.(Jolts))
}
func (h *CostHeap) Pop() any {
old := h.heap
n := len(old)
x := old[n-1]
h.heap = old[0 : n-1]
return x
}
// it doesn't matter what order we push the buttons in --
// only how many times we push each one.
func best(target Jolts, pool []Jolts) int {
var cost = make(map[Jolts]int)
var states []Jolts
states = append(states, Jolts{})
cost[Jolts{}] = 0
for pi, p := range pool {
// enumerate all the states that can be reached by toggling button p
queue := states
fmt.Print(pi, len(states), len(queue))
for _, s := range queue {
here:
for t, c := s, cost[s]; ; {
for i, v := range p {
t[i] += v
if t[i] > target[i] {
// blown target, cut path
break here
}
}
c += 1
if cost_t, ok := cost[t]; ok {
if c < cost_t {
cost[t] = c
}
} else {
cost[t] = c
states = append(states, t)
}
}
}
}
return cost[target]
}