5.3 How not to divide with 3 parties
When first approaching the question of 3-party fair division, it is very tempting to propose this method: Randomly designate one participant to be the divider, and designate the rest choosers. Proceed as follows:
# Math in Society 5.3 -- Why the obvious 3-party method is NOT fair
# "Divider cuts three pieces, chooser 1 picks, chooser 2 picks, divider takes the
# rest." It looks fair. Run it and check the last chooser.
table = {"Chooser 1": [40, 30, 30], # each row is that person's valuation,
"Chooser 2": [45, 30, 25], # as a percent of the whole. EDIT any row.
"Divider": [100/3, 100/3, 100/3]}
PICK_ORDER = ["Chooser 1", "Chooser 2"] # EDIT: reverse this and re-run
people = list(table)
n = len(people)
fair = 100 / n
divider = [p for p in people if p not in PICK_ORDER][0]
print(f"{n} parties, so a fair share is {fair:.1f}% of the whole in your own eyes.")
print(f" {'':<11}" + "".join(f"{'Piece '+str(i+1):>10}" for i in range(n)))
for p in people:
print(f" {p:<11}" + "".join(f"{v:>9.1f}%" for v in table[p]))
left = list(range(n))
got, offered = {}, {}
print()
for p in PICK_ORDER:
offered[p] = list(left)
best = max(left, key=lambda i: table[p][i])
got[p] = best
left.remove(best)
print(f" {p} picks the best piece still on the table: Piece {best+1}"
f", worth {table[p][best]:.1f}%")
got[divider] = left[0]
print(f" {divider} is left with Piece {left[0]+1}, worth {table[divider][left[0]]:.1f}%")
print()
short = []
for p in people:
v = table[p][got[p]]
ok = v >= fair - 1e-9
if not ok:
short.append(p)
print(f" {p:<11} ends with {v:>5.1f}% "
+ ("at least a fair share" if ok else "SHORT -- this division is NOT fair"))
if short:
p = short[0]
menu = ", ".join(f"Piece {i+1} at {table[p][i]:.1f}%" for i in offered[p])
print(f"\n{p} picked last and never had a fair share on offer: the choice was")
print(f" {menu}")
print(f"and nothing there reaches {fair:.1f}%. A method is only fair if a fair")
print("share is guaranteed to be available no matter what the others do first.")
else:
print("\nEveryone did fine THIS time -- but a method is only fair if it works for")
print("every valuation table, not the friendly ones.")
print("\nTry it: change Chooser 2's row to [40, 35, 25] and re-run. Now the method")
print("happens to work. Change it back and reverse PICK_ORDER: the unfairness just")
print("moves to whoever ends up last. The fix is in Section 5.4, Lone Divider.")
1) Have the divider divide the item into 3 pieces
2) Have the first chooser select any of the three pieces they feel is worth a fair share
3) Have the second chooser select either of the remaining pieces
4) The divider gets the piece left.
To handle division with 3 or more parties, we’ll have to take a more clever approach.
Adapted from Math in Society by David Lippman, hosted on LibreTexts (math.libretexts.org) and licensed under CC BY-SA 3.0. Changes were made. License: CC-BY-SA-3.0.