Two Subsets, One Sum
A MoMath Monthly Mindbender: your friend picks ten distinct integers between 1 and 100, and you must find two disjoint nonempty subsets with the same sum. You always win. Ten numbers have 1024 subsets but only 956 possible sums, so the pigeonhole principle forces a collision, and deleting the overlap makes the two subsets disjoint.
Problem
You challenge your bestie to the following game. She chooses 10 distinct integers between 1 and 100; you try to find two disjoint, nonempty subsets of her 10 numbers that have the same sum. With best play, who will win?
Credit: Peter Winkler, Monthly Mindbenders, National Museum of Mathematics, March 2026, based on a problem from the 1972 International Mathematical Olympiad.
You win, whatever she picks
There is no clever set of ten numbers for her to find. The reason is a count, and the count is not close.
Write for her ten numbers and for the sum of a subset . A ten-element set has subsets, counting the empty set and itself. Every subset sum is an integer between , from the empty set, and . Her constraints pin that upper end down: the ten numbers are distinct and none exceeds , so the largest total she can possibly assemble is
So all subset sums land among the integers . There are more subsets than places to put them, a surplus of , and the pigeonhole principle finishes the counting: two distinct subsets satisfy .
Making them disjoint
Nothing so far stops and from overlapping, and in general they do. Throw the overlap away:
Both sets lose exactly the elements of , hence both lose the same total, so
They are disjoint by construction, since anything lying in both and would lie in , which was removed from each.
Nonemptiness is where positivity does its work. Suppose were empty. Then , and because every one of the ten numbers is at least , a subset sums to zero only if it is empty. So is empty too, which forces and , that is , contradicting the two distinct subsets the pigeonhole handed us.
So and are disjoint, nonempty, and equal in sum. You win, against every choice she can make.
How much slack is there
A great deal, and it is worth seeing where it hides. The bound is attained only by , and that set is about the least useful thing she could pick: its numbers sit within of each other, so its subset sums cluster savagely by size. Any set that spreads out to keep sums apart pays for it by pushing the total down, which shrinks the range of sums.
The count survives a much harsher version of itself. Restrict attention to subsets of size at most . There are of them, and each has sum at most , so at most values are available. Since the argument goes through unchanged, and it now delivers a witness in which each of and has at most five elements.
The version set at the 1972 olympiad is tighter still: ten distinct two-digit numbers, so between and , where the largest possible total is . Opening the range down to costs the argument some comfort and none of its force.
Why the range matters
The proof uses nothing about the numbers except that there are ten of them, they are positive, and they are squeezed under . Drop the last condition and the conclusion fails at once. Take the powers of two, and every one of its subsets has a different sum, since a subset sum here is a binary numeral and binary numerals are unique. Your bestie would be delighted with such a set. The trouble is that it has seven elements, not ten, and the next three powers of two are , and , all out of bounds.
Counting says the shortfall is unavoidable. Suppose ten distinct positive integers had all subset sums different. Those sums are distinct integers in , so . If the largest of the ten is then, the numbers being distinct, they are at most , so Hence , giving and so . Ten numbers with all subset sums distinct cannot live below , and the true threshold is higher than this crude bound suggests, since no construction attains it. Capped at she is short by a wide margin, and the surplus of in the first step is the shortfall seen from the other side.
| Quantity | Value |
|---|---|
| subsets of ten numbers | |
| largest possible total, distinct and | |
| available sums | |
| surplus subsets | |
| smallest cap allowing all subset sums distinct | at least |
Computational verification
The proof is short enough to be suspicious of, so the code tests it against the game rather than against the argument. It draws ten distinct numbers, searches all ways of assigning each number to , to , or to neither, and reports the smallest witness found, blocks being searched in order of size so that the first hit is the smallest one. The last part hunts for a set that resists, first at random and then by hill-climbing, with the spread-out sets built from powers of two put in as the natural candidates.
import itertools
import numpy as np
TOP = sum(range(91, 101)) # largest possible total: 91 + ... + 100
print(f"2^10 = {2**10} subsets vs sums 0..{TOP} = {TOP + 1} values: forced")
# every split of the ten numbers into A (+1), B (-1), unused (0), both nonempty,
# grouped by size so the search stops at the smallest witness
C = np.array(list(itertools.product((0, 1, -1), repeat=10)), dtype=np.int64)
C = C[(C > 0).any(1) & (C < 0).any(1)]
BLOCK = [(s, C[np.abs(C).sum(1) == s]) for s in range(2, 11)]
def witness(x): # smallest disjoint equal-sum pair, or None
for s, B in BLOCK:
h = np.flatnonzero(B @ np.asarray(x) == 0)
if h.size:
return s, B[h[0]]
return None, None
rng = np.random.default_rng(2026)
draw = lambda: np.sort(rng.choice(np.arange(1, 101), 10, replace=False))
draws = [draw() for _ in range(20_000)]
sizes = [witness(x)[0] for x in draws]
u, c = np.unique([k for k in sizes if k is not None], return_counts=True)
print(f"witness found in {sum(k is not None for k in sizes) / 200:.1f}%"
f" of 20000; smallest-witness sizes {dict(zip(u.tolist(), c.tolist()))}")
# adversarial: hill-climb, one swap at a time, to push the witness up
hard = draws[int(np.argmax(sizes))]
best, bestset = 0, None
for x in [hard] + [draw() for _ in range(30)]:
k, moved = witness(x)[0], True
while moved:
moved = False
for i in range(10):
for v in np.setdiff1d(np.arange(1, 101), x):
y = np.sort(np.r_[np.delete(x, i), v])
if witness(y)[0] > k:
x, k, moved = y, witness(y)[0], True
if k > best:
best, bestset = k, x
print(f"best adversarial set {bestset.tolist()}: witness uses {best}")
# powers of two keep every subset sum distinct, but they run out below 100
p2 = [1, 2, 4, 8, 16, 32, 64]
sums = np.array(list(itertools.product((0, 1), repeat=7))) @ np.array(p2)
print(f"{p2}: {len(set(sums.tolist()))} distinct sums from {2**7} subsets")
for extra in ([65, 66, 67], [96, 98, 99]):
x = np.array(sorted(p2 + extra))
k, w = witness(x)
A, B = x[w > 0].tolist(), x[w < 0].tolist()
print(f"{x.tolist()}: {A} and {B} both sum to {sum(A)}, size {k}")
# 2^10 = 1024 subsets vs sums 0..955 = 956 values: forced
# witness found in 100.0% of 20000; smallest-witness sizes {3: 17185, 4: 2814, 5: 1}
# best adversarial set [4, 40, 57, 58, 64, 73, 76, 78, 88, 99]: witness uses 5
# [1, 2, 4, 8, 16, 32, 64]: 128 distinct sums from 128 subsets
# [1, 2, 4, 8, 16, 32, 64, 65, 66, 67]: [2, 65] and [67] both sum to 67, size 3
# [1, 2, 4, 8, 16, 32, 64, 96, 98, 99]: [32, 64] and [96] both sum to 96, size 3
2^10 = 1024 subsets vs sums 0..955 = 956 values: forced
random sets: a witness was found in 100.0% of 20000
smallest-witness sizes: {3: 17185, 4: 2814, 5: 1}
hardest random set [4, 40, 57, 58, 64, 73, 76, 78, 88, 99]: smallest witness uses 5
best adversarial set [4, 40, 57, 58, 64, 73, 76, 78, 88, 99]: witness uses 5
[1, 2, 4, 8, 16, 32, 64]: 128 distinct sums from 128 subsets
[1, 2, 4, 8, 16, 32, 64, 65, 66, 67]: [2, 65] and [67] both sum to 67, size 3
[1, 2, 4, 8, 16, 32, 64, 96, 98, 99]: [32, 64] and [96] both sum to 96, size 3
A witness was found every time, as it must be. What the numbers add is a sense of how easy the win is in practice. In of the random sets the smallest witness used three numbers in total, meaning two of her numbers summing to a third; a witness of size two is impossible, since that would need two equal numbers. Only one set in twenty thousand pushed the minimum as high as five, and hill-climbing from that set, swapping one number at a time to make life as hard as possible, could not improve on it.
Padding the powers of two up to ten elements shows the same thing from the other direction. Whichever three numbers under are added to , the crowding at the top of the range hands you a witness immediately: in one case, in the other. The game is not close.