day 23 cleanup part 1

main
magical 2023-12-23 08:35:10 +00:00
parent 7c2e376938
commit d3d175a038
1 changed files with 31 additions and 37 deletions

View File

@ -4,11 +4,7 @@ map = []
for line in input: for line in input:
map.append(list(line.strip())) map.append(list(line.strip()))
# construct a graph # find points where the path forks
for i,c in enumerate(map[0]):
if c == '.':
start = (i,0)
break
def neighbors(x,y): def neighbors(x,y):
n = [] n = []
@ -31,7 +27,9 @@ for i in range(len(map)):
if len(n) not in (0,2): if len(n) not in (0,2):
spots.append((j,i)) spots.append((j,i))
def reachable(start,spots): # construct a graph of paths between fork points
def find_paths(start,spots):
q = [(0,start)] q = [(0,start)]
dist = {} dist = {}
r = [] r = []
@ -53,11 +51,30 @@ def reachable(start,spots):
G = {} G = {}
for p in spots: for p in spots:
G[p] = reachable(p,spots) G[p] = find_paths(p,spots)
print(G) print(G)
# find start position
for i,c in enumerate(map[0]):
if c == '.':
start = (i,0)
break
# algorithm for finding the shortest path between points in a
# a weighted directed acyclic graph
#
# from wikipedia:
# https://en.wikipedia.org/w/index.php?title=Topological_sorting&oldid=1188428695#Application_to_shortest_path_finding
#
# this is a variant of the bellman-ford and shortest path faster algorithms
# except we can take some shortcuts because the graph is acyclic
#
# we implicitly invert the weights of the graph so that, in effect,
# it finds the longest path instead
def topo(G, start): def topo(G, start):
t = [] t = []
seen = set() seen = set()
@ -66,7 +83,7 @@ def topo(G, start):
if n in seen: if n in seen:
return return
if n in tmp: if n in tmp:
raise Exception("cycle with %s %s" % (repr(n),tmp)) raise Exception("cycle with %s %s" % (n,tmp))
tmp.add(n) tmp.add(n)
for _, p in G[n]: for _, p in G[n]:
visit(p) visit(p)
@ -80,36 +97,13 @@ def topo(G, start):
print("topo=",topo(G,start)) print("topo=",topo(G,start))
dist = {n:float('inf') for n in G} dist = {n: float('-inf') for n in G}
pred = {}
dist[start] = 0 dist[start] = 0
T = topo(G, start) T = topo(G, start)
for u in T: for u in T:
for n,v in G[u]: for n,v in G[u]:
w = -n if dist[v] < dist[u] + n:
if dist[v] > dist[u] + w: dist[v] = dist[u] + n
dist[v] = dist[u] + w
pred[v] = u
print(dist) print(dist)
print(-min(dist.values())) print(max(dist.values()))
#import astar
#def goal(state):
# x,y = state
# return y == len(map)-1
#
#M = max(n for p in G for n,_ in G[p])
#
#def nb(state):
# p = state
# for n,q in G[p]:
# yield 1+M-n, q
#
#n, g, path = astar.search(start, goal, nb)
#print(g,path)
#t = 0
#for p, q in zip(path, path[1:]):
# t += sum(n for n,r in G[p] if r == q)
#
#print(t)