jonadab has asked for the wisdom of the Perl Monks concerning the following question:
This is more an algorithm question than Perl per se, but I consider it to be an interesting problem, so...
The basic form of Round Robin tournament schedule with all two-way matches is a reasonably well understood problem, so I won't go into a lot of detail here, but in general the constraints are that each team should quiz each other team at most (ideally, exactly) once, that every team plays the same total number of matches, that no team may play more than one match in any given round, that no team may play against itself, and that when team A plays team B, team B also plays team A at the same time. This is a solved problem.
The following is based on Florence's Algorithm. There may also be other solutions, but here is one.
sub roundrobin { my ($n, $rounds, $bye) = @_; if ($n % 2) { $rounds = $n; $bye = 1; # There will be $rounds rounds with exactly one bye for each team. } else { $rounds = $n - 1; $bye = 0; # There will be $rounds rounds, and every team will quiz every rou +nd. } my $m = $n; ++$m if $n % 2; # $m is the lowest even number greater t +han or equal to $n my %s = (teams => $n, rounds => $rounds, bye => $bye); # The working + schedule. # Fill in the working schedule with a nice diagonal pattern: for my $round (0 .. ($rounds - 1)) { for my $i (0 .. ($round-1)) { $s{table}->[$round]->[$i] = (($rounds + $round - $i + 1) + $m) % + $m; } for my $i ($round .. ($n-1)) { $s{table}->[$round]->[$i] = (($rounds + $round - $i) + $m) % $m; } } use Data::Dumper; print Dumper(+{tentative => \%s}); # Now, do knight-like moves with the 0 (bye) in the first row. # Every time the 0 lands on a number, put that number in the first c +olumn: my $byeround = 0; for my $i (reverse (1 .. ($m - 2))) { $byeround = (($byeround - 2) + $rounds) % $rounds; $s{table}->[$byeround]->[0] = $s{table}->[$byeround]->[$i] || 'Oop +sie'; $s{table}->[$byeround]->[$i] = 0; } # If m != n, then remove team n from all the games, and replace with + -1 (which means a bye, i.e., the team sits out that round): if (not $m == $n) { for my $i (0 .. $rounds-1) { $s{table}->[$i]->[$i] = -1; } } return \%s; }
That's a little too clever for easy maintenance, but it works (I'll spare you the code that checks the results). Well, it works as long as you only have two-way matches, and on modern hardware it's near-instant for any number of teams you're likely to have in this type of tournament. (Once you go past about fifty teams, it's impractical for them all to play eachother anyway, because it would be too many matches for each team, so instead you break into divisions and do double-elimination or somesuch. This algorithm can handle fifty teams in a matter of seconds.)
However, the quizzing program that I'm involved in doesn't just have two-way matches. There are also three-way quizzes. There are several reasons why the three-way quizzes are necessary:
So when constructing schedules for this type of quizzing, the constraints are a bit different...
I've been looking at this problem off and on for a couple of years, but I've never gotten anywhere very useful. Some numbers of teams (e.g., 9) are very easy to do by hand, but others are not, so I'd really like to have an algorithm for doing this. Ideas? What approach should I take? Should I predetermine how many two-way and three-way quizzes there should be, based on the number of teams, or should I approach it from a different direction?
|
|---|
| Replies are listed 'Best First'. | |
|---|---|
|
Re: Round-Robin with Three-way Matches
by kvale (Monsignor) on May 13, 2006 at 17:58 UTC |