2017-day24: recursive backtrack again, bubble up longest bridge and highest sum

This commit is contained in:
alexchao26
2020-12-20 21:36:23 -05:00
parent eb24a4e548
commit 8f8ffc86fa
2 changed files with 144 additions and 0 deletions
+107
View File
@@ -0,0 +1,107 @@
package main
import (
"flag"
"fmt"
"strings"
"github.com/alexchao26/advent-of-code-go/util"
)
func main() {
var part int
flag.IntVar(&part, "part", 1, "part 1 or 2")
flag.Parse()
fmt.Println("Running part", part)
ans := magneticMoat(util.ReadFile("./input.txt"), part)
fmt.Println("Output:", ans)
}
func magneticMoat(input string, part int) int {
edges := getEdges(input)
// start the bridge with a zero
bridge := [][2]int{
{0, 0},
}
usedEdges := map[[2]int]bool{}
for _, edge := range edges {
usedEdges[edge] = false
}
bestStrength, longestBridge := backtrackBridge(bridge, usedEdges)
if part == 1 {
return bestStrength
}
return calcStrengthOfBridge(longestBridge)
}
// backtracking algo that returns strongest bridge
func backtrackBridge(bridge [][2]int, usedEdges map[[2]int]bool) (bestStrength int, longestBridge [][2]int) {
lastVal := bridge[len(bridge)-1][1]
for edge, isUsed := range usedEdges {
// skip edges that are marked as used
if !isUsed {
clonedEdge := edge
// swap the edge vals if the first doesn't match
if clonedEdge[0] != lastVal {
clonedEdge[0], clonedEdge[1] = clonedEdge[1], clonedEdge[0]
}
// if match is found, add it to bridge, mark as used
// add to strength, recurse
if clonedEdge[0] == lastVal {
bridge = append(bridge, clonedEdge)
usedEdges[edge] = true
strength := clonedEdge[0] + clonedEdge[1]
// recurse and bestStrength and longestLength
subStrength, subLongestBridge := backtrackBridge(bridge, usedEdges)
strength += subStrength
// if current bridge is longest (or wins tiebreak) set the longestBridge
if len(bridge) > len(longestBridge) ||
(len(bridge) == len(longestBridge) &&
calcStrengthOfBridge(bridge) > calcStrengthOfBridge(longestBridge)) {
// use this hacky append to create a copy of the bridge slice
// otherwise appends could modify the underlying array
longestBridge = append([][2]int{}, bridge...)
}
// also check if a recursive call had the longest bridge, update longest
if len(subLongestBridge) > len(longestBridge) ||
(len(subLongestBridge) == len(longestBridge) &&
calcStrengthOfBridge(subLongestBridge) > calcStrengthOfBridge(longestBridge)) {
longestBridge = append([][2]int{}, subLongestBridge...)
}
// backtrack
usedEdges[edge] = false
bridge = bridge[:len(bridge)-1]
if strength > bestStrength {
bestStrength = strength
}
}
}
}
return bestStrength, longestBridge
}
func calcStrengthOfBridge(bridge [][2]int) int {
var sum int
for _, edge := range bridge {
sum += edge[0] + edge[1]
}
return sum
}
func getEdges(input string) (edges [][2]int) {
for _, line := range strings.Split(input, "\n") {
var pair [2]int
fmt.Sscanf(line, "%d/%d", &pair[0], &pair[1])
edges = append(edges, pair)
}
return edges
}
+37
View File
@@ -0,0 +1,37 @@
package main
import (
"testing"
"github.com/alexchao26/advent-of-code-go/util"
)
var example = `0/2
2/2
2/3
3/4
3/5
0/1
10/1
9/10`
func Test_magneticMoat(t *testing.T) {
tests := []struct {
name string
input string
part int
want int
}{
{"example_part1", example, 1, 31},
{"actual_part1", util.ReadFile("input.txt"), 1, 1868},
{"example_part2", example, 2, 19},
{"actual_part2", util.ReadFile("input.txt"), 2, 1841},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
if got := magneticMoat(tt.input, tt.part); got != tt.want {
t.Errorf("magneticMoat() = %v, want %v", got, tt.want)
}
})
}
}