Library · The Fiddler: Solutions · Chapter 138
How Long Would It Take to Pick a Speaker at Random?
The members of the majority party must choose a Speaker from three candidates. Each member votes for one of the candidates completely at random, even the candidates themselves. If someone wins a majority, they become Speaker. Otherwise the candidate with the fewest votes is eliminated (one of them at random if several tie for fewest) and the party votes again, at random, among the rest. A second round, if needed, is sure to produce a Speaker. What is the average number of rounds?
The Fiddler, Zach Wissner-Gross, October 27, 2023(original post)
The official solution appeared in the post of November 3, 2023 and gives about rounds for the main puzzle and about for the Extra Credit. Both agree with the answers below.
Solution
A second round has two candidates and an odd number of voters, , so one of them must get at least votes. The only question is how often the first round already has a winner. Call that probability . Then the number of rounds is with probability and otherwise, and the average is
A majority means at least of the votes. Two candidates cannot both have that many, so the chance that somebody has a majority is just three times the chance that a particular candidate, A, does. Each voter picks A with probability , independently, so the number of votes for A follows the binomial distribution:
How big is this? A expects votes, with a standard deviation of . A majority needs , more than five standard deviations above the average, so is tiny. The sum is a finite one that can be evaluated exactly; its first term, , already supplies about half of it, and the total is . So Almost always it takes both rounds.
The computation
The program counts ballots exactly. For candidates it builds, one voter at a time, the number of ways the voters can cast their ballots so that A gets each possible number of votes; the count of ballot lists in which A has a majority, times , over all ballot lists, is the chance of a winner. It then runs the elimination process as a recursion: one round, and if nobody won, the same race with one fewer candidate.
from fractions import Fraction
VOTERS = 221
def majority_chance(c):
"""Exact chance that some candidate gets a majority when
each of the 221 voters picks one of c candidates at
random. ways[a] counts ballot lists giving candidate A
exactly a votes, built up one voter at a time; at most
one candidate can hold a majority, so multiply by c."""
ways = [1]
for _ in range(VOTERS):
new = [0] * (len(ways) + 1)
for a, w in enumerate(ways):
new[a + 1] += w # this voter picks A
new[a] += w * (c - 1) # picks someone else
ways = new
wins = sum(ways[VOTERS // 2 + 1:])
return Fraction(c * wins, c ** VOTERS)
def expected_rounds(c):
"""Rounds needed starting from c candidates: one round,
then (if nobody won) the race with one fewer."""
if c == 1:
return Fraction(0)
p = majority_chance(c)
return 1 + (1 - p) * expected_rounds(c - 1)
print(f"main: {float(expected_rounds(3)):.10f}")
It prints
main: 1.9999995111
Extra Credit
Now there are candidates. On average, how many rounds until someone wins a majority of the votes?
Solution
Each round either produces a Speaker or removes exactly one candidate, and the next round starts afresh with random votes among those left. Which candidate was eliminated does not matter, only how many remain. Write for the average number of rounds starting with candidates and for the chance of a majority in a round with candidates. Then , and As in the main puzzle, , and with more candidates a majority is even more out of reach: is about , and is about . So the race almost surely runs all the way down to two candidates: seven rounds take it from candidates to , and from there it behaves like the main puzzle, needing more rounds on average. Unrolling the recursion, since the main effect of each tiny is to save the rounds that would have followed, and only is large enough to show. So
The computation
The same recursion from The computation above, started from candidates:
print(f"extra credit: {float(expected_rounds(10)):.10f}")
It prints
extra credit: 8.9999995111