From Matt Gold, a chance, perhaps, to redeem your busted bracket:

On Monday, Villanova won the NCAA men’s basketball national title. But I recently overheard some boisterous Butler fans calling themselves the “transitive national champions,” because Butler beat Villanova earlier in the season. Of course, other teams also beat Butler during the season and their fans could therefore make exactly the same claim.2

How many transitive national champions were there this season? Or, maybe more descriptively, how many teams weren’t transitive national champions?

(All of this season’s college basketball results are here. To get you started, Villanova lost to Butler, St. John’s, Providence and Creighton this season, all of whom can claim a transitive title. But remember, teams beat those teams, too.)

https://fivethirtyeight.com/features/when-will-the-arithmetic-anarchists-attack/


In [1]:
from pathlib import Path
from collections import namedtuple, defaultdict
import itertools

In [2]:
games = Path('scores.txt').read_text().split('\n')

In [3]:
def parse_game_text(line):
    team_1 = line[12:36].strip()
    team_2 = line[41:65].strip()
    score_1 = int(line[36:39])
    score_2 = int(line[65:68])
    
    return (team_1, team_2)

In [4]:
loser_dict = defaultdict(set)
all_teams_set = set()
for winner, loser in [parse_game_text(game) for game in games]:
    loser_dict[loser].add(winner)
    all_teams_set.add(winner)
    all_teams_set.add(loser)

In [5]:
len(all_teams_set)


Out[5]:
1362

In [6]:
new_transitive_winners = {'Villanova'}
transitive_winners = new_transitive_winners

while new_transitive_winners:
    all_transitive_winners = set.union(*[loser_dict[winner] for winner in new_transitive_winners])
    new_transitive_winners = all_transitive_winners - transitive_winners
    transitive_winners |= new_transitive_winners
    print(len(transitive_winners))


5
23
90
196
323
384
476
647
868
1041
1136
1180
1185
1185

In [7]:
len(all_teams_set) - len(transitive_winners)


Out[7]:
177