names = ["A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L"]
days = [2, 2, 3, 2, 3, 5, 3, 3, 3, 4, 2, 1]
after = [[], ["A"], ["B"], ["B"], ["C"], ["C"], ["C"], ["D", "E"],
["F", "G", "H"], ["D"], ["I", "J"], ["K"]]
dur = dict(zip(names, days))
pred = dict(zip(names, after))
es, ef = {}, {}
for t in names: # forward pass
es[t] = max((ef[p] for p in pred[t]), default=0)
ef[t] = es[t] + dur[t]
end = max(ef.values())
ls, lf = {}, {}
for t in reversed(names): # backward pass
succ = [s for s in names if t in pred[s]]
lf[t] = min((ls[s] for s in succ), default=end)
ls[t] = lf[t] - dur[t]
for t in names:
slack = ls[t] - es[t]
line = f"{t} ES {es[t]:2} EF {ef[t]:2} LS {ls[t]:2} LF {lf[t]:2} slack {slack}"
if slack == 0:
line += " critical"
print(line)
print("Project length:", end, "days")