-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathba5d.py
69 lines (56 loc) · 1.76 KB
/
ba5d.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
# Find the Longest Path in a DAG
from math import inf
from copy import deepcopy
from collections import defaultdict
# A "reverse" graph, from each node to all incoming nodes
def incoming(graph):
x = defaultdict(list)
k = list(graph.keys())
k += [x["n"] for v in graph.values() for x in v]
for g in list(set(k)):
for node in graph[g]:
x[node["n"]] += [{"n": g, "w": node["w"]}]
return x
# Nodes with no incoming edges.
def sources(graph):
inc = incoming(graph)
return [g for g in graph if len(inc[g]) == 0]
def topological_order(graph):
graph = deepcopy(graph)
order = []
candidates = sources(graph)
while candidates:
n = candidates[0]
order.append(n)
candidates.remove(n)
graph[n] = []
candidates = list(set(sources(graph)) - set(order))
return order
def longest_path(graph, src, sink):
score = {}
path = defaultdict(list)
for node in graph:
score[node] = -inf
score[src] = 0
path[src] = [src]
inc = incoming(graph)
order = topological_order(graph)
for node in order[order.index(src) + 1 :]:
if len(inc[node]):
scores = [score[pre["n"]] + pre["w"] for pre in inc[node]]
score[node] = max(scores)
i = scores.index(max(scores))
path[node] = path[inc[node][i]["n"]] + [node]
return score[sink], path[sink]
def parse_graph(graph):
g = defaultdict(list)
for x in graph:
n, o = x.split("->")
node, weight = o.split(":")
g[n] += [{"n": node, "w": int(weight)}]
return g
def main(file):
source, sink, *graph = open(file).read().splitlines()
score, path = longest_path(parse_graph(graph), source, sink)
print(score)
print(*path, sep="->")