我正在尝试解决个人项目中的算法问题。
这是一个与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 = ____ : ____
请注意,Match i
和Match i+1
同时播放if i%2==1
可以进行多少个不同的比赛?这些比赛是哪些?
我尝试了一种蛮力的方法,但是它太慢了。有更好的算法吗?
代码。尤其是python
答案 0 :(得分:1)
问题是高度对称的,让我以更紧凑的形式编写
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
对于8个玩家,有28个可能的团队,由两个人组成(AB,AC,AD ...),并且全部都出现在表中,每个正好出现一次。 AB和BA是同一支球队,我会选择第一种形式,因为它是字母顺序。 AB CD和AB CD是相同的搭配,我会选择第一种形式。 AB CD + EF GH和EF GH + AB CD只是比赛的排列,我会选择第一种形式。考虑到所有这些,我们将问题减少到在该模式中填充21个单词
AB __ + __ __
AC __ + __ __
AD __ + __ __
AE __ + __ __
AF __ + __ __
AG __ + __ __
AH __ + __ __
这样,每一行包含所有8个字母,每个字母恰好一次。而且这很容易被强行强制执行,大约花了15秒钟来计算(不向控制台写入组合),结果是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();
}
唯一棘手的部分是SolutionIsOK
函数。它解决了最后一个未解决的对称问题。这两种情况相等:
AC BD + EG FH
AD BC + EH FG
AC BD + EH FG
AD BC + EG FH
因为只对第二个匹配进行了排列。仅当那些匹配包含相同的4个人时,才能对第二个匹配进行排列。可以检测到这种情况,我们只能选择按字母顺序排序的情况。而这正是SolutionIsOK
的作用。
答案 1 :(得分:0)
您可以检查constraint satisfaction problem。这是关于SAT求解器或SMT求解器的。
也许您的问题可以定义为CS问题。
可以解决CS问题的示例库:
我知道我给你的是库,而不是算法,但是也许不需要重新发明轮子。