package main import ( "fmt" "math/rand" "strings" h "git.bullercodeworks.com/brian/adventofcode/helpers" ) type component struct { id string connections map[string]component conns map[string]bool } type components struct { all map[string]component edges []connections } type connections struct { from, to string track []string } func main() { lines := h.StdinToStringSlice() var comps components var edges []connections var counter int var tries int for tries < 100 { counter = 0 for { counter++ compsS := components{all: make(map[string]component)} for _, line := range lines { connect(&compsS, line) } cc := minCut(compsS) cuts := len(cc.edges) edges = cc.edges comps = compsS if cuts == 3 { break } if counter >= 100 { break } } tries++ if counter < 100 { break } } total := cutInGroups(&comps, edges) fmt.Println(total) } func connect(comps *components, line string) { split := strings.Split(line, ": ") nodeName := split[0] connectionsNames := strings.Split(split[1], " ") node := component{id: nodeName, connections: make(map[string]component), conns: make(map[string]bool)} if _, ok := comps.all[nodeName]; !ok { comps.all[nodeName] = node } for _, neighborName := range connectionsNames { neighbor := component{id: neighborName, connections: make(map[string]component), conns: make(map[string]bool)} if _, ok := comps.all[neighborName]; !ok { comps.all[neighborName] = neighbor } comps.all[nodeName].connections[neighborName] = neighbor comps.all[nodeName].conns[neighborName] = true comps.all[neighborName].connections[nodeName] = node comps.all[neighborName].conns[nodeName] = true comps.edges = append(comps.edges, connections{ from: nodeName, to: neighborName, track: []string{nodeName, neighborName}, }) } } func minCut(comps components) components { cc := components{ all: make(map[string]component), edges: comps.edges, } for key, val := range comps.all { cc.all[key] = val } for len(cc.all) > 2 { u, v := randomComps(&cc) contract(&cc, u, v) } return cc } func randomComps(comps *components) (component, component) { randomN := rand.Intn(len(comps.edges)) edge := comps.edges[randomN] comps.edges = append(comps.edges[:randomN], comps.edges[randomN+1:]...) randCorn := rand.Intn(2) var nameU, nameV string if randCorn == 0 { nameU = edge.from nameV = edge.to } else { nameU = edge.to nameV = edge.from } u, v := comps.all[nameU], comps.all[nameV] return u, v } func contract(comps *components, u component, v component) { delete(comps.all, v.id) delete(comps.all[u.id].connections, v.id) for _, node := range comps.all { if _, ok := node.connections[v.id]; ok { delete(node.connections, v.id) node.connections[u.id] = u comps.all[u.id].connections[node.id] = node } } for i := 0; i < len(comps.edges); { if comps.edges[i].from == v.id { comps.edges[i].from = u.id } if comps.edges[i].to == v.id { comps.edges[i].to = u.id } if comps.edges[i].from == comps.edges[i].to { comps.edges = append(comps.edges[:i], comps.edges[i+1:]...) continue } i++ } } func cutInGroups(comps *components, edges []connections) int { var final1, final2 string for i, edge := range edges { cut1 := edge.track[0] cut2 := edge.track[1] delete(comps.all[cut1].conns, cut2) delete(comps.all[cut2].conns, cut1) if i == len(edges)-1 { final1 = cut1 final2 = cut2 } } group1 := countN(comps, final1) group2 := countN(comps, final2) return group1 * group2 } func countN(comps *components, start string) int { visited := make(map[string]bool) counter := 0 entry := start path := []string{entry} for len(path) > 0 { currentPath := path[0] path = path[1:] if _, ok := visited[currentPath]; ok { continue } counter++ currentcomponent := comps.all[currentPath] visited[currentPath] = true for key := range currentcomponent.conns { if _, ok := visited[key]; ok { continue } path = append(path, key) } } return counter }