day 10 part 2 but it's too slow
This commit is contained in:
parent
0fb22d2358
commit
c2717ae9ab
156
day10/sol2.go
Normal file
156
day10/sol2.go
Normal file
@ -0,0 +1,156 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"container/heap"
|
||||
"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
|
||||
}
|
||||
|
||||
func best(target Jolts, pool []Jolts) int {
|
||||
var cost = make(map[Jolts]int)
|
||||
h := &CostHeap{nil, cost}
|
||||
heap.Push(h, Jolts{})
|
||||
for h.Len() > 0 {
|
||||
s := heap.Pop(h).(Jolts)
|
||||
if s == target {
|
||||
break
|
||||
}
|
||||
// enumerate all the states that can be reached by toggling button p
|
||||
next:
|
||||
for _, p := range pool {
|
||||
t := s
|
||||
for i, v := range p {
|
||||
t[i] += v
|
||||
if t[i] > target[i] {
|
||||
// blown target, cut path
|
||||
continue next
|
||||
}
|
||||
}
|
||||
|
||||
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
|
||||
heap.Push(h, t)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return cost[target]
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user