【问题标题】:compute all possible combinations given some constrains在给定一些约束的情况下计算所有可能的组合
【发布时间】:2020-11-06 22:01:12
【问题描述】:

我正在尝试为个人项目解决这个算法问题。

  1. 本次比赛共有 8 名选手参加。
  2. 他们玩 2vs2
  3. 同时进行两场比赛(这样所有 8 名玩家都在比赛)
  4. 每位玩家必须与所有其他玩家(在同一支球队)打 7 场比赛
  5. 在比赛结束时,每位选手打了 7 场比赛。
  6. 锦标赛共由 14 场比赛组成
  7. 比赛的排列不计入新锦标赛。 (即比赛被定义为一组比赛)

这是一个包含玩家 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 iMatch i+1同时播放if i%2==1

问题:

可能有多少种不同的锦标赛?这些是哪些锦标赛?

我尝试了一种蛮力方法,但它太慢了。有没有更好的算法?

编辑:

欢迎使用代码。特别是python

【问题讨论】:

  • 您尝试的内容似乎符合称为 Shomate 运动锦标赛的重复桥牌个人锦标赛的要求。 en.wikipedia.org/wiki/…
  • 不受约束,有(7!)^7不同的锦标赛。因此,有了这些限制,它就会少一些。

标签: algorithm performance combinatorics


【解决方案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 所做的。

【讨论】:

  • 谢谢。代码是C还是java?我无法运行它
  • @Donbeo 它是 C#
  • 谢谢。我从来没有用过它。我需要了解如何运行它:-D
【解决方案2】:

您可以查看constraint satisfaction problem。这是关于SAT求解器或SMT求解器。

也许你的问题可以定义为 CS 问题。

可以解决 CS 问题的示例库:

我知道我给你的是库,而不是算法,但也许没有必要重新发明轮子。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-12-30
    • 2023-03-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多