220 lines
6.3 KiB
Go
220 lines
6.3 KiB
Go
package common
|
|
|
|
import (
|
|
"bufio"
|
|
"fmt"
|
|
"strconv"
|
|
"strings"
|
|
)
|
|
|
|
|
|
type Valve struct {
|
|
name string
|
|
rate int
|
|
tunnels map[*Valve]struct{}
|
|
distances map[*Valve]int
|
|
}
|
|
|
|
func (valve *Valve) GetBestPathFromValveWithHelper(otherValves map[*Valve]int, minutesLeft int, helperValve *Valve, helperMinutesLeft int) int {
|
|
max := 0
|
|
current := 0
|
|
|
|
if minutesLeft > 0 {
|
|
current += (minutesLeft - 1) * valve.rate
|
|
}
|
|
if helperMinutesLeft > 0 {
|
|
current += (helperMinutesLeft - 1) * helperValve.rate
|
|
}
|
|
|
|
if minutesLeft > 0 || helperMinutesLeft > 0 {
|
|
for relevantValve := range(otherValves) {
|
|
done := false
|
|
if minutesLeft <= 0 {
|
|
done = true
|
|
}
|
|
if minutesLeft - valve.distances[relevantValve] <= 0 {
|
|
relevantValve = valve
|
|
minutesLeft = 0
|
|
}
|
|
|
|
for relevantValve2 := range(otherValves) {
|
|
helperDone := false
|
|
if helperMinutesLeft <= 0 {
|
|
helperDone = true
|
|
}
|
|
if helperMinutesLeft - helperValve.distances[relevantValve2] <= 0 {
|
|
relevantValve2 = helperValve
|
|
helperMinutesLeft = 0
|
|
}
|
|
|
|
if relevantValve != relevantValve2 {
|
|
currentRelevantValves := make(map[*Valve]int)
|
|
for relevantValve3, relevantValveRate3 := range(otherValves) {
|
|
if relevantValve != relevantValve3 && relevantValve2 != relevantValve3 {
|
|
currentRelevantValves[relevantValve3] = relevantValveRate3
|
|
}
|
|
}
|
|
currentMax := relevantValve.GetBestPathFromValveWithHelper(currentRelevantValves, minutesLeft - 1 - valve.distances[relevantValve],
|
|
relevantValve2, helperMinutesLeft - 1 - helperValve.distances[relevantValve2])
|
|
if currentMax > max {
|
|
max = currentMax
|
|
}
|
|
} else if len(otherValves) == 1 {
|
|
currentMax := relevantValve.GetBestPathFromValveWithHelper(make(map[*Valve]int), minutesLeft - 1 - valve.distances[relevantValve],
|
|
helperValve, 0)
|
|
if currentMax > max {
|
|
max = currentMax
|
|
}
|
|
currentMax = valve.GetBestPathFromValveWithHelper(make(map[*Valve]int), 0,
|
|
relevantValve2, helperMinutesLeft - 1 - helperValve.distances[relevantValve2])
|
|
if currentMax > max {
|
|
max = currentMax
|
|
}
|
|
}
|
|
|
|
if helperDone {
|
|
break
|
|
}
|
|
}
|
|
|
|
if done {
|
|
break
|
|
}
|
|
}
|
|
}
|
|
|
|
return max + current
|
|
}
|
|
|
|
func (valve *Valve) GetBestPathFromValve(otherValves map[*Valve]int, minutesLeft int) int {
|
|
if minutesLeft <= 0 {
|
|
return 0
|
|
}
|
|
|
|
current := (minutesLeft - 1) * valve.rate
|
|
max := 0
|
|
|
|
for relevantValve := range(otherValves) {
|
|
currentRelevantValves := make(map[*Valve]int)
|
|
for relevantValve2, relevantValveRate2 := range(otherValves) {
|
|
if relevantValve != relevantValve2 {
|
|
currentRelevantValves[relevantValve2] = relevantValveRate2
|
|
}
|
|
}
|
|
currentMax := relevantValve.GetBestPathFromValve(currentRelevantValves, minutesLeft - 1 - valve.distances[relevantValve])
|
|
if currentMax > max {
|
|
max = currentMax
|
|
}
|
|
}
|
|
|
|
return max + current
|
|
}
|
|
|
|
|
|
type Volcano struct {
|
|
valves []*Valve
|
|
current *Valve
|
|
rate int
|
|
pressure int
|
|
minutesLeft int
|
|
}
|
|
|
|
func (volcano *Volcano) GetBestPath(minutesLeft int, helper bool) int {
|
|
relevantValves := make(map[*Valve]int)
|
|
for valve := range volcano.valves {
|
|
if volcano.valves[valve].rate > 0 {
|
|
relevantValves[volcano.valves[valve]] = volcano.valves[valve].rate
|
|
}
|
|
}
|
|
|
|
if helper {
|
|
return volcano.current.GetBestPathFromValveWithHelper(relevantValves, minutesLeft + 1, volcano.current, minutesLeft + 1)
|
|
} else {
|
|
return volcano.current.GetBestPathFromValve(relevantValves, minutesLeft + 1)
|
|
}
|
|
}
|
|
|
|
func (volcano *Volcano) ComputeDistances() bool {
|
|
changesFound := false
|
|
for valveSource := range volcano.valves {
|
|
for valveTarget1 := range volcano.valves[valveSource].distances {
|
|
for valveTarget2 := range volcano.valves[valveSource].distances {
|
|
d, ok := valveTarget1.distances[valveTarget2]
|
|
newDistance := volcano.valves[valveSource].distances[valveTarget1] +
|
|
volcano.valves[valveSource].distances[valveTarget2]
|
|
if !ok || newDistance < d {
|
|
valveTarget1.distances[valveTarget2] = newDistance
|
|
valveTarget2.distances[valveTarget1] = newDistance
|
|
changesFound = true
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return changesFound
|
|
}
|
|
|
|
func (volcano *Volcano) Print() {
|
|
for i := range(volcano.valves) {
|
|
fmt.Print(volcano.valves[i].name)
|
|
fmt.Print(": ")
|
|
fmt.Println(volcano.valves[i].rate)
|
|
for valve, d := range(volcano.valves[i].distances) {
|
|
fmt.Print(" ")
|
|
fmt.Print(valve.name)
|
|
fmt.Print(": ")
|
|
fmt.Println(d)
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
func Parse(scanner bufio.Scanner) Volcano {
|
|
volcano := Volcano{}
|
|
volcano.valves = []*Valve{}
|
|
destinations := make(map[string][]string)
|
|
|
|
for scanner.Scan() {
|
|
line := scanner.Text()
|
|
splittedLine := strings.Split(line, " ")
|
|
name := splittedLine[1]
|
|
rate, _ := strconv.Atoi(splittedLine[4][5:len(splittedLine[4])-1])
|
|
destinations[name] = []string{}
|
|
for i := 9; i < len(splittedLine); i++ {
|
|
destinations[name] = append(destinations[name], splittedLine[i][0:2])
|
|
}
|
|
volcano.valves = append(volcano.valves, &Valve{name, rate, map[*Valve]struct{}{}, make(map[*Valve]int)})
|
|
}
|
|
|
|
for valveName, currDestinations := range(destinations) {
|
|
var valveSource *Valve
|
|
for i := range volcano.valves {
|
|
if volcano.valves[i].name == valveName {
|
|
valveSource = volcano.valves[i]
|
|
valveSource.distances[valveSource] = 0
|
|
break
|
|
}
|
|
}
|
|
for _, destination := range currDestinations {
|
|
var valveDestination *Valve
|
|
for i := range volcano.valves {
|
|
if volcano.valves[i].name == destination {
|
|
valveDestination = volcano.valves[i]
|
|
}
|
|
}
|
|
valveSource.tunnels[valveDestination] = struct{}{}
|
|
valveSource.distances[valveDestination] = 1
|
|
}
|
|
}
|
|
|
|
for i := range(volcano.valves) {
|
|
if volcano.valves[i].name == "AA" {
|
|
volcano.current = volcano.valves[i]
|
|
}
|
|
}
|
|
volcano.minutesLeft = 30
|
|
|
|
for volcano.ComputeDistances() {}
|
|
|
|
return volcano
|
|
}
|