import heapq def solve(input): G = {} V = [] for line in open(input): parts = line.split() v = parts.pop(0).strip(':') V.append(v) G[v] = parts sinks = [e for edges in G.values() for e in edges if e not in V] V += sinks for v in sinks: G[v] = [] # reversed graph R = {} for v, E in G.items(): for e in E: R.setdefault(e, []).append(v) # topological sort # T is an order of vertices such that each vertex is # listed _after_ all the vertices connected to its incoming edges. T = [] seen = set() def visit(v): if v not in seen: seen.add(v) for e in R.get(v,()): visit(e) T.append(v) visit('out') #T.reverse() #print(T) def paths(start,end): Q = [(0,start)] seen = set() paths = {v:0 for v in V} paths[start] = 1 for v in T: if v in seen: continue seen.add(v) for e in G[v]: paths[e] += paths[v] #print(paths) return paths[end] if 'you' in G: # Part 1: # find all paths from you -> out print(paths('you', 'out')) if 'svr' in G: # Part 2: find all paths that pass through # svr -> fft -> dac -> out, or # svr -> dac -> fft -> out. sf = paths('svr', 'fft') sd = paths('svr', 'dac') fd = paths('fft', 'dac') df = paths('dac', 'fft') do = paths('dac', 'out') fo = paths('fft', 'out') print(sf*fd*do + sd*df*fo) solve("sample") solve("sample2") solve("input")