/
17.go
98 lines (89 loc) · 1.78 KB
/
17.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
package main
import (
"github.com/cespare/next/container/heap"
)
func init() {
addSolutions(17, problem17)
}
func problem17(ctx *problemContext) {
var c city
scanner := ctx.scanner()
for scanner.scan() {
c.g.addRow([]byte(scanner.text()))
}
ctx.reportLoad()
ctx.reportPart1(c.bestPath(1, 3))
ctx.reportPart2(c.bestPath(4, 10))
}
type city struct {
g grid[byte]
}
type cityState struct {
p vec2
v vec2 // previous move (in reverse search)
n int // number of consecutive steps taken in the v direction
}
type cityQueueState struct {
state cityState
cost int64
idx int
}
func (c *city) bestPath(minMove, maxMove int) int64 {
h := heap.New(func(c0, c1 *cityQueueState) bool {
return c0.cost < c1.cost
})
byState := make(map[cityState]*cityQueueState)
h.SetIndex = func(e *cityQueueState, i int) {
e.idx = i
}
seed := &cityQueueState{
state: cityState{
p: vec2{0, 0},
},
}
targ := vec2{c.g.cols - 1, c.g.rows - 1}
byState[seed.state] = seed
h.Push(seed)
for h.Len() > 0 {
e := h.Pop()
if e.state.p == targ && e.state.n >= minMove {
return e.cost
}
delete(byState, e.state)
for _, v := range nesw {
if v == e.state.v.mul(-1) {
continue
}
if e.state.n == maxMove && v == e.state.v {
continue
}
if e.state.n > 0 && e.state.n < minMove && v != e.state.v {
continue
}
p := e.state.p.add(v)
if !c.g.contains(p) {
continue
}
state := cityState{
p: p,
v: v,
n: 1,
}
if v == e.state.v {
state.n = e.state.n + 1
}
cost := e.cost + int64(c.g.at(p)-'0')
if e1, ok := byState[state]; ok {
if cost < e1.cost {
e1.cost = cost
h.Fix(e1.idx)
}
continue
}
qs := &cityQueueState{state: state, cost: cost}
byState[state] = qs
h.Push(qs)
}
}
panic("no solution")
}