Compare commits
No commits in common. "5fd80e56d877c2806f031aa1276eae846df67265" and "a0714336899dbbbe1025eb513efc14aa6b0f6225" have entirely different histories.
5fd80e56d8
...
a071433689
142
day10/sol2.go
142
day10/sol2.go
@ -24,14 +24,6 @@ func main() {
|
|||||||
solve("input")
|
solve("input")
|
||||||
}
|
}
|
||||||
|
|
||||||
// Brilliant insight from a redditor:
|
|
||||||
// suppose we only want to match the parity of the required joltages.
|
|
||||||
// we can use our solution for part 1 to find the minimum number of button presses
|
|
||||||
// to make that happen. now, consider what happens if we press a button twice:
|
|
||||||
// it won't change the parity at all, only add 2 to some joltages. ok.
|
|
||||||
// take the 2nd bit of each joltage. what's the minimum number of double-presses
|
|
||||||
// required to match that pattern? and so on.
|
|
||||||
|
|
||||||
func solve(filename string) {
|
func solve(filename string) {
|
||||||
input, err := os.Open(filename)
|
input, err := os.Open(filename)
|
||||||
check(err)
|
check(err)
|
||||||
@ -43,19 +35,14 @@ func solve(filename string) {
|
|||||||
line := scanner.Text()
|
line := scanner.Text()
|
||||||
parts := strings.Fields(line)
|
parts := strings.Fields(line)
|
||||||
parts = parts[1:]
|
parts = parts[1:]
|
||||||
var buts []uint32
|
var jolts []Jolts
|
||||||
var target Jolts
|
|
||||||
for _, p := range parts {
|
for _, p := range parts {
|
||||||
j, err := parseJolt(p)
|
j, err := parseJolt(p)
|
||||||
check(err)
|
check(err)
|
||||||
if p[0] == '{' {
|
jolts = append(jolts, j)
|
||||||
target = j
|
|
||||||
} else {
|
|
||||||
buts = append(buts, j.uint32())
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
fmt.Printf("%v %b %v\n", target, buts, parts)
|
fmt.Printf("%v %v\n", jolts, parts)
|
||||||
n := solveJolts(target, buts)
|
n := best(jolts[len(jolts)-1], jolts[:len(jolts)-1])
|
||||||
fmt.Printf("%s = %v\n", line, n)
|
fmt.Printf("%s = %v\n", line, n)
|
||||||
total += n
|
total += n
|
||||||
//fmt.Println(n)
|
//fmt.Println(n)
|
||||||
@ -102,89 +89,62 @@ func parseJoltByValue(s string) (Jolts, error) {
|
|||||||
return j, nil
|
return j, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (j *Jolts) uint32() (u uint32) {
|
// An CostHeap is a min-heap of ints.
|
||||||
for i, v := range j {
|
type CostHeap struct {
|
||||||
if v != 0 {
|
heap []Jolts
|
||||||
u |= uint32(1) << i
|
cost map[Jolts]int
|
||||||
}
|
|
||||||
}
|
|
||||||
return u
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (j Jolts) Sub(m uint32, value int) Jolts {
|
func (h *CostHeap) Len() int { return len(h.heap) }
|
||||||
for i := range j {
|
func (h *CostHeap) Less(i, j int) bool { return h.cost[h.heap[i]] < h.cost[h.heap[j]] }
|
||||||
if m>>i&1 != 0 {
|
func (h *CostHeap) Swap(i, j int) { h.heap[i], h.heap[j] = h.heap[j], h.heap[i] }
|
||||||
j[i] -= int16(value)
|
|
||||||
}
|
func (h *CostHeap) Push(x any) {
|
||||||
}
|
// Push and Pop use pointer receivers because they modify the slice's length,
|
||||||
return j
|
// not just its contents.
|
||||||
|
h.heap = append(h.heap, x.(Jolts))
|
||||||
}
|
}
|
||||||
|
|
||||||
func (j Jolts) Valid() bool {
|
func (h *CostHeap) Pop() any {
|
||||||
for i := range j {
|
old := h.heap
|
||||||
if j[i] < 0 {
|
n := len(old)
|
||||||
return false
|
x := old[n-1]
|
||||||
}
|
h.heap = old[0 : n-1]
|
||||||
}
|
return x
|
||||||
return true
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: this isn't quite enough. we need to know not only how many button presses
|
// it doesn't matter what order we push the buttons in --
|
||||||
// a mask can be solved in, but also *the specific buttons* -- because even though
|
// only how many times we push each one.
|
||||||
// each button is pressed at most once, two buttons can be connected to the same
|
|
||||||
// output so the joltages can be between like 0-10. this needs to be subtracted
|
|
||||||
// from the target, and two different button patterns can have different effects
|
|
||||||
// on the target.
|
|
||||||
//
|
|
||||||
// the good news is that we can cache and reuse the cost map computed in best(),
|
|
||||||
// since it depends only on the button wiring. all that's left after that is a
|
|
||||||
// graph search through the state space, using masks to prune each level.
|
|
||||||
|
|
||||||
func solveJolts(target Jolts, pool []uint32) int {
|
func best(target Jolts, pool []Jolts) int {
|
||||||
var bits uint32
|
var cost = make(map[Jolts]int)
|
||||||
for _, x := range target {
|
var states []Jolts
|
||||||
bits |= uint32(x)
|
states = append(states, Jolts{})
|
||||||
}
|
cost[Jolts{}] = 0
|
||||||
var answer int
|
for pi, p := range pool {
|
||||||
for bit := uint(0); bits>>bit > 0; bit++ {
|
|
||||||
var mask uint32
|
|
||||||
for i := range target {
|
|
||||||
mask |= uint32(target[i]) >> bit << i
|
|
||||||
}
|
|
||||||
|
|
||||||
if mask == 0 {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
n := best(mask, pool)
|
|
||||||
answer += n << bit
|
|
||||||
|
|
||||||
//for i, p := range pool {
|
|
||||||
// if mask>>i&1 != 0 {
|
|
||||||
// target.Sub(p, 1)
|
|
||||||
// }
|
|
||||||
//}
|
|
||||||
}
|
|
||||||
return answer
|
|
||||||
}
|
|
||||||
|
|
||||||
func best(target uint32, pool []uint32) int {
|
|
||||||
var cost = make(map[uint32]int)
|
|
||||||
var states = []uint32{0}
|
|
||||||
cost[0] = 0
|
|
||||||
for _, p := range pool {
|
|
||||||
// enumerate all the states that can be reached by toggling button p
|
// enumerate all the states that can be reached by toggling button p
|
||||||
for _, s := range states {
|
queue := states
|
||||||
t := s ^ p
|
fmt.Print(pi, len(states), len(queue))
|
||||||
c := cost[t] + 1
|
for _, s := range queue {
|
||||||
|
here:
|
||||||
if cost_t, ok := cost[t]; ok {
|
for t, c := s, cost[s]; ; {
|
||||||
if c < cost_t {
|
for i, v := range p {
|
||||||
cost[t] = c
|
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)
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
cost[t] = c
|
|
||||||
states = append(states, t)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -15,27 +15,9 @@ def solve(input):
|
|||||||
M = sympy.Matrix(matrix + [target]).T
|
M = sympy.Matrix(matrix + [target]).T
|
||||||
#print(repr(M))
|
#print(repr(M))
|
||||||
S, pivots = M.rref()
|
S, pivots = M.rref()
|
||||||
if len(pivots) == BTNS:
|
if len(pivots) < BTNS:
|
||||||
# solved
|
|
||||||
presses = S.col(-1)
|
|
||||||
print("*", target, presses.T, sum(presses))
|
|
||||||
part2 += sum(presses)
|
|
||||||
else:
|
|
||||||
# not solved
|
# not solved
|
||||||
# the system of equations is underdetermined, either because
|
print(repr(S))
|
||||||
# we started with too few equations or because some of them were
|
|
||||||
# not linearly independent.
|
|
||||||
# the upshot is that we have one or more free variables
|
|
||||||
# (in practice 1-3 free variables) so if we just iterate
|
|
||||||
# through all legal values for those variables we should
|
|
||||||
# be able to find a solution?
|
|
||||||
# unfortunately i am still running into some unsolveable cases
|
|
||||||
# and i'm not sure why.
|
|
||||||
|
|
||||||
#if BTNS - len(pivots) >= 3:
|
|
||||||
# print(repr(S))
|
|
||||||
#continue
|
|
||||||
|
|
||||||
coords = []
|
coords = []
|
||||||
limits = []
|
limits = []
|
||||||
extra_rows = []
|
extra_rows = []
|
||||||
@ -64,6 +46,10 @@ def solve(input):
|
|||||||
part2 += min(totals)
|
part2 += min(totals)
|
||||||
else:
|
else:
|
||||||
print("uhoh", target)
|
print("uhoh", target)
|
||||||
|
else:
|
||||||
|
presses = S.col(-1)
|
||||||
|
print("*", target, presses.T, sum(presses))
|
||||||
|
part2 += sum(presses)
|
||||||
print(part2)
|
print(part2)
|
||||||
#print(less, greater)
|
#print(less, greater)
|
||||||
|
|
||||||
|
|||||||
@ -1,18 +0,0 @@
|
|||||||
sizes = [7, 7, 7, 6, 7, 5]
|
|
||||||
|
|
||||||
t = 0
|
|
||||||
for line in open("input"):
|
|
||||||
if 'x' in line:
|
|
||||||
line = line.strip()
|
|
||||||
s = line.replace("x"," ").replace(":","").split()
|
|
||||||
n = map(int, s)
|
|
||||||
w, h, *n = n
|
|
||||||
need = sum(sizes[i]*x for i,x in enumerate(n))
|
|
||||||
if need > w*h:
|
|
||||||
print(line, "impossible")
|
|
||||||
else:
|
|
||||||
print(line, "<>", w*h - need)
|
|
||||||
t += 1
|
|
||||||
|
|
||||||
print(t)
|
|
||||||
|
|
||||||
1030
day12/input
1030
day12/input
File diff suppressed because it is too large
Load Diff
Loading…
x
Reference in New Issue
Block a user