Reputation: 17617
I am trying to solve this algorithmic problem for a personal project.
This is an example tournament with players A,B,C,D,E,F,G,H:
Match 1 : A, B VS C, D. Score = ____ : ____
Match 2 : E, F VS H, G. Score = ____ : ____
Match 3 : C, A VS B, D. Score = ____ : ____
Match 4 : E, G VS H, F. Score = ____ : ____
Match 5 : A, D VS C, B. Score = ____ : ____
Match 6 : H, E VS F, G. Score = ____ : ____
Match 7 : E, A VS B, F. Score = ____ : ____
Match 8 : C, G VS H, D. Score = ____ : ____
Match 9 : A, F VS E, B. Score = ____ : ____
Match 10 : H, C VS D, G. Score = ____ : ____
Match 11 : A, G VS H, B. Score = ____ : ____
Match 12 : C, E VS D, F. Score = ____ : ____
Match 13 : H, A VS B, G. Score = ____ : ____
Match 14 : C, F VS E, D. Score = ____ : ____
Note that Match i
and Match i+1
are played at the same time if i%2==1
How many different tournaments are possible? Which are these tournaments?
I tried a sort of brute force approach but it is too slow. Is there any better algorithm?
code is welcome. Especially python
Upvotes: 1
Views: 601
Reputation: 6103
The problem is highly symmetric Let me write it in more compact form
AB CD + EF GH
AC BD + EG FH
AD BC + EH FG
AE BF + CG DH
AF BE + CH DG
AG BH + CE DF
AH BG + CF DE
For 8 players, there are 28 possible teams of two people (AB, AC, AD...) and all are present in the table, each exactly once. AB and BA is the same team, I would choose the first form as it is alphabetical order. AB CD and CD AB is the same match, I would choose the first form. AB CD + EF GH and EF GH + AB CD is just permutation of matches, I would choose the first form. Given all this we reduced the problem to filling 21 words into this schema
AB __ + __ __
AC __ + __ __
AD __ + __ __
AE __ + __ __
AF __ + __ __
AG __ + __ __
AH __ + __ __
in such a way, that every row contains all 8 letters, each exactly once. And this can be easily brute forced, it took about 15 seconds to calculate (without writing combinations to the console), the result is 10034775
static bool SolutionIsOK(string[,] matchesTuples)
{
for (int i = 1; i < 7; ++i)
{
for (int j = 0; j < i; ++j)
{
string a1 = matchesTuples[j, 2];
string a2 = matchesTuples[i, 2];
if (a1[0] > a2[0] || a1[0] == a2[0] && a1[1] > a2[1])
{
string b1 = matchesTuples[j, 3];
string b2 = matchesTuples[i, 3];
int check1 = (1 << (a1[0] - 'A')) |
(1 << (a1[1] - 'A')) |
(1 << (b1[0] - 'A')) |
(1 << (b1[1] - 'A'));
int check2 = (1 << (a2[0] - 'A')) |
(1 << (a2[1] - 'A')) |
(1 << (b2[0] - 'A')) |
(1 << (b2[1] - 'A'));
if (check1 == check2) { return false; }
}
}
}
return true;
}
static void WriteSolution(string[,] matchesTuples)
{
for (int i = 0; i < 7; ++i)
{
Console.WriteLine(matchesTuples[i, 0] + " " + matchesTuples[i, 1] + " + "
+ matchesTuples[i, 2] + " " + matchesTuples[i, 3]);
}
Console.WriteLine("------------------------------");
}
static int counter = 0;
static void placeTeam(int level, string[] teams, string[,] matchesTuples, bool[,] presentPlayers)
{
if (level == teams.Length)
{
if (!SolutionIsOK(matchesTuples)) { return; };
WriteSolution(matchesTuples);
counter++; // solution found
return;
}
string team = teams[level++];
for (int i = 0; i < 7; ++i)
{
if (presentPlayers[i, team[0] - 'A']
|| presentPlayers[i, team[1] - 'A'])
{
continue;
}
presentPlayers[i, team[0] - 'A'] = true;
presentPlayers[i, team[1] - 'A'] = true;
for (int j = 1; j < 4; ++j)
{
if (matchesTuples[i, j] != null) { continue; }
if (j == 3 && (matchesTuples[i, 2] == null)) { continue; }
matchesTuples[i, j] = team;
placeTeam(level, teams, matchesTuples, presentPlayers);
matchesTuples[i, j] = null;
}
presentPlayers[i, team[0] - 'A'] = false;
presentPlayers[i, team[1] - 'A'] = false;
}
}
static void Main(string[] args)
{
string[,] matchesTuples = new string[7, 4]; // AE BF + CG DH
bool[,] presentPlayers = new bool[7, 8]; // ABCDEFGH
string[] teams = new string[28]; // AB, AC, AD, ..., BC, BD, ..., GH
int i = 0;
for (char c1 = 'A'; c1 < 'H'; ++c1)
{
for (char c2 = c1; ++c2 <= 'H';)
{
teams[i] = c1.ToString() + c2;
if (c1 == 'A')
{
matchesTuples[i, 0] = teams[i];
presentPlayers[i, c1 - 'A'] = true;
presentPlayers[i, c2 - 'A'] = true;
}
++i;
}
}
placeTeam(7, teams, matchesTuples, presentPlayers);
Console.WriteLine("Found " + counter);
Console.ReadKey();
}
the only tricky part is the SolutionIsOK
function. It solves the last remaining symmetry that was not addressed. Those two cases are equal:
AC BD + EG FH
AD BC + EH FG
AC BD + EH FG
AD BC + EG FH
because the second match is only permutated. The second match can be permutated only if those matches contain the same 4 people. This case can be detected and we can choose only the case that is alphabetically ordered. And that is exactly what SolutionIsOK
does.
Upvotes: 1
Reputation: 2700
You can check constraint satisfaction problem. It is about SAT solver or SMT solver.
Maybe your problem can be defined as CS problem.
Example libraries that can resolve CS problems:
I know I give you libraries, not algorithm, but maybe there's no need reinvent the wheel.
Upvotes: 0