···11+import sys
22+import re
33+import fileinput
44+55+66+class Disc:
77+ def __init__(self, name, weight, aboves):
88+ self.name = name
99+ self.weight = int(weight)
1010+ self.aboves = aboves
1111+ self.below = None
1212+1313+1414+RE_DISC = re.compile(r'(\w+) \((\d+)\)(?: -> (.+))?')
1515+DISCS = {}
1616+1717+# Process input
1818+for line in fileinput.input():
1919+ name, weight, aboves = RE_DISC.findall(line.strip())[0]
2020+2121+ weight = int(weight)
2222+ aboves = aboves.split(', ') if aboves else []
2323+2424+ DISCS[name] = Disc(name, weight, aboves)
2525+2626+2727+# Link discs to their parent/children
2828+for d in DISCS.values():
2929+ for a in d.aboves:
3030+ DISCS[a].below = d
3131+ d.aboves = [DISCS[a] for a in d.aboves]
3232+3333+3434+# Search for the bottom-most disc
3535+for d in DISCS.values():
3636+ if d.below is None:
3737+ root = d
3838+3939+print 'Name of bottom program:', root.name
4040+4141+4242+def program_weight(node):
4343+ if not node.aboves:
4444+ return node.weight
4545+4646+ weights = [program_weight(a) for a in node.aboves]
4747+4848+ # Since we're performing DFS, we are guaranteed to encounter the problem
4949+ # disc here first; therefore, we compute the correct answer and exit.
5050+ if len(set(weights)) != 1:
5151+ for i, w in enumerate(weights):
5252+ if weights.count(w) == 1:
5353+ diff = w
5454+ wrong_disc = node.aboves[i].name
5555+ else:
5656+ same = w
5757+5858+ proper_weight = DISCS[wrong_disc].weight + (same - diff)
5959+ print "Proper weight of `{}`: {}".format(wrong_disc, proper_weight)
6060+ sys.exit()
6161+6262+ return sum(weights) + node.weight
6363+6464+6565+# Initialize the recursion, which will also find the solution.
6666+program_weight(root)