day25: wow, part 1
This commit is contained in:
parent
a9caa4c8f1
commit
b879b6541a
File diff suppressed because it is too large
Load Diff
|
@ -1,15 +1,15 @@
|
|||
flowchart LR
|
||||
bvb --- cmg
|
||||
hfx --- ntq
|
||||
frs --- lsr
|
||||
flowchart TD
|
||||
cmg --- qnr
|
||||
cmg --- lhk
|
||||
jqt --- nvd
|
||||
lhk --- lsr
|
||||
bvb --- ntq
|
||||
bvb --- rhn
|
||||
bvb --- xhk
|
||||
frs --- rsh
|
||||
pzl --- rsh
|
||||
jqt --- ntq
|
||||
lhk --- nvd
|
||||
lsr --- pzl
|
||||
lhk --- lsr
|
||||
lsr --- rsh
|
||||
hfx --- ntq
|
||||
qnr --- rzs
|
||||
cmg --- rzs
|
||||
bvb --- hfx
|
||||
lhk --- nvd
|
||||
frs --- qnr
|
||||
jqt --- ntq
|
||||
rhn --- xhk
|
||||
|
|
|
@ -1,34 +1,34 @@
|
|||
flowchart TD
|
||||
ntq --- xhk
|
||||
bvb --- hfx
|
||||
lsr --- pzl
|
||||
nvd --- qnr
|
||||
lhk --- lsr
|
||||
nvd --- pzl
|
||||
rhn --- xhk
|
||||
jqt --- rhn
|
||||
cmg --- lhk
|
||||
pzl --- rsh
|
||||
frs --- lhk
|
||||
bvb --- cmg
|
||||
jqt --- xhk
|
||||
frs --- lsr
|
||||
lsr --- rsh
|
||||
hfx --- pzl
|
||||
hfx --- xhk
|
||||
frs --- lhk
|
||||
pzl --- rsh
|
||||
jqt --- ntq
|
||||
hfx --- ntq
|
||||
lhk --- nvd
|
||||
lsr --- rzs
|
||||
bvb --- xhk
|
||||
frs --- rsh
|
||||
qnr --- rzs
|
||||
bvb --- rhn
|
||||
bvb --- hfx
|
||||
jqt --- rhn
|
||||
hfx --- xhk
|
||||
frs --- lsr
|
||||
lhk --- lsr
|
||||
jqt --- nvd
|
||||
cmg --- rzs
|
||||
cmg --- nvd
|
||||
bvb --- ntq
|
||||
ntq --- xhk
|
||||
frs --- qnr
|
||||
rsh --- rzs
|
||||
hfx --- rhn
|
||||
hfx --- pzl
|
||||
bvb --- xhk
|
||||
rhn --- xhk
|
||||
frs --- rsh
|
||||
cmg --- qnr
|
||||
nvd --- qnr
|
||||
qnr --- rzs
|
||||
bvb --- ntq
|
||||
frs --- qnr
|
||||
cmg --- nvd
|
||||
hfx --- rhn
|
||||
jqt --- ntq
|
||||
hfx --- ntq
|
||||
lsr --- rsh
|
||||
cmg --- lhk
|
||||
rsh --- rzs
|
||||
lhk --- nvd
|
||||
lsr --- rzs
|
||||
|
|
106
day25/graph.go
106
day25/graph.go
|
@ -68,8 +68,9 @@ func (g *Graph) readGraphLine(l string) {
|
|||
return
|
||||
}
|
||||
|
||||
// NOTE this is so sad. nodeA.Neighbors.Remove(nodeB.Name) hangs for a reason i don't understand
|
||||
func (g *Graph) RemoveEdge(a, b string) {
|
||||
log.Printf("entering remove edge for %s and %s", a, b)
|
||||
// log.Printf("entering remove edge for %s and %s", a, b)
|
||||
nodeA, existsA := g.Nodes[a]
|
||||
// log.Println("got first node", nodeA, existsA)
|
||||
nodeB, existsB := g.Nodes[b]
|
||||
|
@ -79,52 +80,52 @@ func (g *Graph) RemoveEdge(a, b string) {
|
|||
}
|
||||
|
||||
// log.Println("before removals")
|
||||
newANeighbors := mapset.NewSet[string]()
|
||||
for oldNeighbor := range nodeA.Neighbors.Iter() {
|
||||
if oldNeighbor != nodeB.Name {
|
||||
newANeighbors.Add(oldNeighbor)
|
||||
}
|
||||
}
|
||||
log.Println("before remove first", nodeA)
|
||||
nodeA.Neighbors = newANeighbors
|
||||
// log.Println("before remove first", nodeA)
|
||||
// nodeA.Neighbors = newANeighbors
|
||||
nodeA.Neighbors = nodeA.Neighbors.Difference(mapset.NewSet[string](nodeB.Name))
|
||||
// nodeA.Neighbors.Remove(nodeB.Name)
|
||||
log.Println("removed first", nodeA)
|
||||
// log.Println("removed first", nodeA)
|
||||
|
||||
newBNeighbors := mapset.NewSet[string]()
|
||||
for oldNeighbor := range nodeB.Neighbors.Iter() {
|
||||
if oldNeighbor != nodeA.Name {
|
||||
newBNeighbors.Add(oldNeighbor)
|
||||
}
|
||||
}
|
||||
log.Println("before remove second", nodeB)
|
||||
nodeB.Neighbors = newBNeighbors
|
||||
// log.Println("before remove second", nodeB)
|
||||
// nodeB.Neighbors = newBNeighbors
|
||||
nodeB.Neighbors = nodeB.Neighbors.Difference(mapset.NewSet[string](nodeA.Name))
|
||||
// nodeB.Neighbors.Remove(nodeA.Name)
|
||||
log.Println("removed second", nodeB)
|
||||
// log.Println("removed second", nodeB)
|
||||
}
|
||||
|
||||
func (g *Graph) AddEdge(a, b string) {
|
||||
nodeA, existsA := g.Nodes[a]
|
||||
nodeB, existsB := g.Nodes[b]
|
||||
if !existsA || !existsB {
|
||||
panic("requesting not found node")
|
||||
}
|
||||
nodeA.Neighbors.Add(nodeB.Name)
|
||||
nodeB.Neighbors.Add(nodeA.Name)
|
||||
}
|
||||
|
||||
func (g *Graph) findCycle() (from, to string, exists bool) {
|
||||
log.Printf(">>>> starting new find cycle")
|
||||
// log.Printf(">>>> starting new find cycle")
|
||||
var firstNode *Node
|
||||
for _, n := range g.Nodes {
|
||||
firstNode = n
|
||||
break
|
||||
}
|
||||
log.Printf("initial search from %s and neighbors %+v", firstNode.Name, firstNode.Neighbors)
|
||||
// log.Printf("initial search from %s and neighbors %+v", firstNode.Name, firstNode.Neighbors)
|
||||
for neighborName := range firstNode.Neighbors.Iter() {
|
||||
initialVisited := mapset.NewSet[string](firstNode.Name)
|
||||
log.Printf("initial dfs from %s to %s with initial visited %+v", firstNode.Name, neighborName, initialVisited)
|
||||
// log.Printf("initial dfs from %s to %s with initial visited %+v", firstNode.Name, neighborName, initialVisited)
|
||||
from, to, exists = g.dfcCycle(firstNode.Name, neighborName, initialVisited)
|
||||
if exists {
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
log.Printf("<<<< cycle %t, from %s to %s", exists, from, to)
|
||||
// log.Printf("<<<< cycle %t, from %s to %s", exists, from, to)
|
||||
return
|
||||
}
|
||||
|
||||
func (g *Graph) dfcCycle(fromName, atName string, visited mapset.Set[string]) (cycleFrom, cycleTo string, cycleExists bool) {
|
||||
log.Printf("> step from %+v to %+v. visited : %+v", fromName, atName, visited)
|
||||
// log.Printf("> step from %+v to %+v. visited : %+v", fromName, atName, visited)
|
||||
if visited.Cardinality() == len(g.Nodes) {
|
||||
log.Println("exit by visited all")
|
||||
return
|
||||
|
@ -215,6 +216,9 @@ func (g *Graph)SaveAsMermaid(filename string) {
|
|||
type Edge struct {
|
||||
smaller, bigger string
|
||||
}
|
||||
func (e Edge)String() string {
|
||||
return fmt.Sprintf("%s/%s", e.smaller, e.bigger)
|
||||
}
|
||||
|
||||
func CreateEdge(a, b string) Edge {
|
||||
var smaller, bigger string
|
||||
|
@ -235,7 +239,7 @@ func (g *Graph) RemoveAllCycles() (removedEdges mapset.Set[Edge]) {
|
|||
for hasCycle {
|
||||
from, to, hasCycle = g.findCycle()
|
||||
if hasCycle {
|
||||
log.Printf("\n!!!! found cycle %s to %s\n", from, to)
|
||||
// log.Printf("\n!!!! found cycle %s to %s\n", from, to)
|
||||
edgeToRemove := CreateEdge(from, to)
|
||||
removedEdges.Add(edgeToRemove)
|
||||
g.RemoveEdge(from, to)
|
||||
|
@ -243,3 +247,55 @@ func (g *Graph) RemoveAllCycles() (removedEdges mapset.Set[Edge]) {
|
|||
}
|
||||
return
|
||||
}
|
||||
|
||||
func (g *Graph) TryToSplit() (componentSizeMult int) {
|
||||
// first remove all cycles
|
||||
removedEdges := g.RemoveAllCycles()
|
||||
g.SaveAsMermaid("after-removing-cycles.mmd")
|
||||
// log.Printf("all removed edges %+v, two of them are necessary to split initial graph into 2 ", removedEdges)
|
||||
|
||||
triedEdges := mapset.NewSet[Edge]()
|
||||
|
||||
for _, node := range g.Nodes {
|
||||
for neighborName := range node.Neighbors.Iter() {
|
||||
edge := CreateEdge(neighborName, node.Name)
|
||||
if triedEdges.Contains(edge) {
|
||||
continue
|
||||
}
|
||||
triedEdges.Add(edge)
|
||||
// first remove the edge
|
||||
g.RemoveEdge(edge.bigger, edge.smaller)
|
||||
|
||||
// then ask for components of the nodes of removed edge
|
||||
compA := g.ComponentFrom(edge.bigger)
|
||||
compB := g.ComponentFrom(edge.smaller)
|
||||
|
||||
// iterate over the initially removed edges. only two of them should be 'connecting'
|
||||
// i.e were necessary to remove
|
||||
necessaryEdgesCount := 0
|
||||
for initiallyRemovedEdge := range removedEdges.Iter() {
|
||||
endA, endB := initiallyRemovedEdge.bigger, initiallyRemovedEdge.smaller
|
||||
isNonNecessary := (compA.Contains(endA) && compA.Contains(endB)) || (compB.Contains(endA) && compB.Contains(endB))
|
||||
if !isNonNecessary {
|
||||
// log.Printf("with edge %+v test removed, the %+v also seems necessary", edge, initiallyRemovedEdge)
|
||||
necessaryEdgesCount += 1
|
||||
}
|
||||
}
|
||||
// log.Printf("with edge %+v test removed neessary count is %d", edge, necessaryEdgesCount)
|
||||
|
||||
// if we found 2 necessary, then our currently tried edge is the third necesary to remove
|
||||
// and out two components are the searched
|
||||
if necessaryEdgesCount == 2 {
|
||||
return compA.Cardinality() * compB.Cardinality()
|
||||
}
|
||||
|
||||
// in the end add edge back if not fitting
|
||||
g.AddEdge(edge.bigger, edge.smaller)
|
||||
}
|
||||
}
|
||||
|
||||
// now huh. if we didn't find `necessaryEdgesCount == 2`
|
||||
// that means 0, 1 or 3
|
||||
|
||||
return
|
||||
}
|
||||
|
|
|
@ -2,6 +2,8 @@ package day25
|
|||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
mapset "github.com/deckarep/golang-set/v2"
|
||||
)
|
||||
|
||||
func TestReadFileExample(t *testing.T) {
|
||||
|
@ -54,7 +56,41 @@ func TestRemoveAllCycles(t *testing.T) {
|
|||
g.SaveAsMermaid("example-before-removing.mmd")
|
||||
t.Logf("initial graph is %+v", g)
|
||||
edges := g.RemoveAllCycles()
|
||||
expectedNecessary := mapset.NewSet[Edge](
|
||||
CreateEdge("hfx", "pzl"),
|
||||
CreateEdge("bvb", "cmg"),
|
||||
CreateEdge("nvd", "jqt"),
|
||||
)
|
||||
|
||||
intersection := expectedNecessary.Intersect(edges)
|
||||
t.Logf("i expect that exactly two will be in intersection %+v", intersection)
|
||||
if intersection.Cardinality() != 2 {
|
||||
panic("huh?")
|
||||
// ok, this is not what i expected.
|
||||
// this is unstable. but i could run it several times? and hopefully luck out?
|
||||
}
|
||||
|
||||
t.Logf("removed edges %+v", edges)
|
||||
t.Logf("after removal graph is %+v", g)
|
||||
g.SaveAsMermaid("example-after-removing.mmd")
|
||||
}
|
||||
|
||||
func TestSplittingExample(t *testing.T) {
|
||||
filename := "example"
|
||||
g := ReadGraphFile(filename)
|
||||
result := g.TryToSplit()
|
||||
t.Logf("hopefully same as example answer: %d", result)
|
||||
}
|
||||
|
||||
func TestSplittingInput(t *testing.T) {
|
||||
// kind of brute force
|
||||
result := 0
|
||||
filename := "input"
|
||||
|
||||
for result == 0 {
|
||||
g := ReadGraphFile(filename)
|
||||
result = g.TryToSplit()
|
||||
t.Logf("hopefully as answer: %d", result)
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -456,3 +456,25 @@ PASS
|
|||
ok sunshine.industries/aoc2023/day25 0.003s
|
||||
|
||||
#+end_src
|
||||
** kind of bruteforce
|
||||
graph_test.go:93: hopefully as answer: 0
|
||||
graph_test.go:93: hopefully as answer: 0
|
||||
graph_test.go:93: hopefully as answer: 0
|
||||
graph_test.go:93: hopefully as answer: 0
|
||||
graph_test.go:93: hopefully as answer: 0
|
||||
graph_test.go:93: hopefully as answer: 0
|
||||
graph_test.go:93: hopefully as answer: 0
|
||||
graph_test.go:93: hopefully as answer: 0
|
||||
graph_test.go:93: hopefully as answer: 0
|
||||
graph_test.go:93: hopefully as answer: 0
|
||||
graph_test.go:93: hopefully as answer: 0
|
||||
graph_test.go:93: hopefully as answer: 0
|
||||
graph_test.go:93: hopefully as answer: 0
|
||||
graph_test.go:93: hopefully as answer: 0
|
||||
graph_test.go:93: hopefully as answer: 0
|
||||
graph_test.go:93: hopefully as answer: 0
|
||||
graph_test.go:93: hopefully as answer: 0
|
||||
graph_test.go:93: hopefully as answer: 518391
|
||||
graph_test.go:93: hopefully as answer: 0
|
||||
graph_test.go:93: hopefully as answer: 518391
|
||||
graph_test.go:93: hopefully as answer: 0
|
||||
|
|
Loading…
Reference in New Issue