Well, unfortunately, I don't have time to generate the chart, but it
was easy enough to generate the pairings...  This could probably be
easily golfed, but I figured just leave it be.

The output is "stacked" array pairs... What I mean by that is that the
top array has two items: left and right. Each of those items is an
array of two items: left and right.... etc until you get down to the
leaves.  A pair like [1, 2] means "Team 1 vs Team 2", while a pair
like [6, nil] means "Team 6 gets a bye."

class Integer
def ceilPow2
n = self - 1
i = 1
until (n >> i).zero?
n |= (n >> i)
i *= 2
end
n += 1
end

def even?
(self % 2).zero?
end
end

class Array
def fold
raise ArgumentError unless size.even?
h = size / 2
self[0,h].zip(self[h,h].reverse)
end
end

def matchup(n)
raise ArgumentError unless n > 0

byes = n.ceilPow2 - n
mups = (1..n).to_a + [nil] * byes

until mups.size == 1
mups = mups.fold
end

mups[0]
end

def report(mups)
# Here is where you could do tree output or similar... but I've no time.
p mups
end

numTeams = (ARGV[0] || 23).to_i
if numTeams < 2
puts "C'mon, that's not much of a competition..."
else
matchUps = matchup(numTeams)
report(matchUps)
end