9

我在实现这个小循环项目时遇到了一些麻烦。我尝试做的是生成游戏的预览日历

然后我想输出;

第 1 天:第 1 队对第 2 队;第 3 队对第 4 队;5 队对 6 队;

第 2 天第 1 队与第 4 队;第 6 队对第 3 队;第 2 队对第 5 队;

直到锦标赛结束;

这是到目前为止我得到的代码,但我无法让第一个团队在阵列的其余部分旋转时修复......:

static void Main(string[] args)
   {
        string[] ListTeam = new string[] {"Equipe1", "Equipe2", "Equipe3", "Equipe4", "Equipe5", "Equipe6"};
        IList<Match> ListMatch = new List<Match>();
        it NumberOfDays = (ListTeam.Count()-1);
        int y = 2;

        for (int i = 1; i <= NumberOfDays; i++)
        {
            Console.WriteLine("\nDay {0} : \n",i);
            Console.WriteLine(ListTeam[0].ToString() + " VS " + ListTeam[i].ToString());

            for (y =ListTeam.Count(); y>0 ; y--)
            {
                Console.WriteLine(ListTeam[y].ToString() + " VS " + ListTeam[y+1].ToString());
                y++;
            }

        }
    }

编辑:我在java中找到了一个代码示例,但我无法翻译它......

4

8 回答 8

13

使用模运算应该很容易做到这一点:

更新2:(如承诺的正确算法)

public void ListMatches(List<string> ListTeam)
{
    if (ListTeam.Count % 2 != 0)
    {
        ListTeam.Add("Bye");
    }

    int numDays = (numTeams - 1);
    int halfSize = numTeams / 2;

    List<string> teams = new List<string>();

    teams.AddRange(ListTeam.Skip(halfSize).Take(halfSize));
    teams.AddRange(ListTeam.Skip(1).Take(halfSize -1).ToArray().Reverse());

    int teamsSize = teams.Count;

    for (int day = 0; day < numDays; day++)
    {
        Console.WriteLine("Day {0}", (day + 1));

        int teamIdx = day % teamsSize;

        Console.WriteLine("{0} vs {1}", teams[teamIdx], ListTeam[0]);

        for (int idx = 1; idx < halfSize; idx++)
        {               
            int firstTeam = (day + idx) % teamsSize;
            int secondTeam = (day  + teamsSize - idx) % teamsSize;
            Console.WriteLine("{0} vs {1}", teams[firstTeam], teams[secondTeam]);
        }
    }
}

这将打印每天的团队比赛。

让我快速尝试解释该算法的工作原理:

我注意到,由于我们正在轮换除第一个团队之外的所有团队,如果我们将除第一个团队之外的所有团队放入一个数组中,那么我们应该使用基于日期的索引偏移量从该数组中读取第一个团队并执行模算术正确环绕。在实践中,我们会将该数组视为在两个方向上无限重复,并且我们将逐渐向右(或向左)滑动我们的视图。

然而,有一个障碍,那就是我们必须以一种非常特殊的方式命令团队才能正常工作。否则,我们不会得到正确的旋转。正因为如此,我们也需要以一种非常特殊的方式阅读匹配的二队。

准备清单的正确方法如下:

  • 永远不要将第一支球队(Team#1)放在列表​​中。
  • 将团队列表的后半部分放在列表的最前面。
  • 取列表的前半部分,将其反转并将它们放入列表中(但不是 Team#1)。

现在,读取列表的正确方法如下:

  • 对于每一天,将您正在查看的第一个索引增加1.
  • 对于您在该位置看到的第一支球队,将该球队与 Team#1 匹配。
  • 对于列表中的下一支球队((day + idx) % numDays),我们通常会将其与偏移一半球队数减 1 的球队进行匹配(减 1,因为我们自己处理了第一场比赛)。但是,由于我们列表的后半部分是通过还原准备的,因此我们需要在已还原的列表的后半部分中匹配该偏移量。一个更简单的方法是观察 in this 相当于匹配相同的索引,但从列表的末尾开始。给定当前的day偏移量(day + (numDays - idx)) % numDays

更新 3:我不高兴我的解决方案涉及如此复杂的选择、匹配、反转数组元素。在我考虑了我的解决方案所涉及的内容后,我意识到我太执着于保持团队的既定顺序。但是,这不是一项要求,并且可以通过不关心初始订购来获得不同但同样有效的时间表。重要的是我在解释的第二部分中描述的选择算法。

因此,您可以简化以下几行:

teams.AddRange(ListTeam.Skip(halfSize).Take(halfSize));
teams.AddRange(ListTeam.Skip(1).Take(halfSize -1).ToArray().Reverse());

到:

teams.AddRange(ListTeam); // Copy all the elements.
teams.RemoveAt(0); // To exclude the first team.
于 2009-08-18T10:59:54.610 回答
6

听起来您想安排一场循环赛。wp文章包含算法。

我什至看不到您在哪里尝试旋转阵列。排列看起来像: 1 -> 2 -> 3 -> 4 ... -> n/2 - 1 -> n - 1 -> n - 2 -> n - 3 -> ... -> n /2 -> 1(并且 0 保持不变)。您可以在 2 个循环中执行此操作(顶行和底行)。

于 2009-08-17T16:04:54.710 回答
2

我对计算双循环调度的已回答代码块进行了一些改进

GameEntities db = new GameEntities();


private void btnTeamFixtures_Click(object sender, RoutedEventArgs e)
    {
        txtResults.Text = null;

        var allTeams = db.Team.Select(t => t.TeamName);

        int numDays = allTeams.Count() - 1;
        int halfsize = allTeams.Count() / 2;

        List<string> temp = new List<string>();
        List<string> teams = new List<string>();

        teams.AddRange(allTeams);
        temp.AddRange(allTeams);
        teams.RemoveAt(0);

        int teamSize = teams.Count;

        for (int day = 0; day < numDays * 2; day++)
        {
            //Calculate1stRound(day);
            if (day % 2 == 0)
            {
                txtResults.Text += String.Format("\n\nDay {0}\n", (day + 1));

                int teamIdx = day % teamSize;

                txtResults.Text += String.Format("{0} vs {1}\n", teams[teamIdx], temp[0]);

                for (int idx = 0; idx < halfsize; idx++)
                {
                    int firstTeam = (day + idx) % teamSize;
                    int secondTeam = ((day + teamSize) - idx) % teamSize;

                    if (firstTeam != secondTeam)
                    {
                        txtResults.Text += String.Format("{0} vs {1}\n", teams[firstTeam], teams[secondTeam]);
                    }
                }
            }

            //Calculate2ndRound(day);
            if (day % 2 != 0)
            {
                int teamIdx = day % teamSize;

                txtResults.Text += String.Format("\n\nDay {0}\n", (day + 1));

                txtResults.Text += String.Format("{0} vs {1}\n", temp[0], teams[teamIdx]);

                for (int idx = 0; idx < halfsize; idx++)
                {
                    int firstTeam = (day + idx) % teamSize;
                    int secondTeam = ((day + teamSize) - idx) % teamSize;

                    if (firstTeam != secondTeam)
                    {
                        txtResults.Text += String.Format("{0} vs {1}\n", teams[secondTeam], teams[firstTeam]);
                    }
                }
            }
        }
    }

如果你想要你可以创建 2 个方法并像我在 2 个注释行中所做的那样传递和整数(Day),以分隔代码。

如果您有任何问题或建议,请随时回复。

于 2011-09-14T19:55:00.543 回答
1

这可能是一种复杂的方法,但这可以简化为图论问题。为每个团队创建一个图顶点,并在每个顶点之间创建一条边(因此它是一个完整的图)。然后对于算法:

对于每一天 i = 1 .. n :

  • 选择任何两个直接连接的未标记顶点,并用 i 标记它们之间的边。标记两个顶点。
  • 重复直到标记所有顶点。
  • 输出标记的边(即team1 vs team2,team3 vs team4等)
  • 从图中删除标记的边并将所有顶点重置为未标记。
于 2009-08-18T11:26:40.700 回答
1

根据@paracycle 的回答,我提供了一个更好的代码,并进行了以下更改:

  • 我的方法是基于泛型的T
  • 我的代码不会更改原始teams列表实例
  • 提高代码质量
public static IEnumerable<(int Day, T First, T Second)> ListMatches<T>(IList<T> teams)
{
    var matches = new List<(int, T, T)>();
    if (teams == null || teams.Count < 2)
    {
        return matches;
    }

    var restTeams = new List<T>(teams.Skip(1));
    var teamsCount = teams.Count;
    if (teams.Count % 2 != 0)
    {
        restTeams.Add(default);
        teamsCount++;
    }

    for (var day = 0; day < teamsCount - 1; day++)
    {
        if (restTeams[day % restTeams.Count]?.Equals(default) == false)
        {
            matches.Add((day, teams[0], restTeams[day % restTeams.Count]));
        }

        for (var index = 1; index < teamsCount / 2; index++)
        {
            var firstTeam = restTeams[(day + index) % restTeams.Count];
            var secondTeam = restTeams[(day + restTeams.Count - index) % restTeams.Count];
            if (firstTeam?.Equals(default) == false && secondTeam?.Equals(default) == false)
            {
                matches.Add((day, firstTeam, secondTeam));
            }
        }
    }

    return matches;
}

测试它的代码:

foreach (var match in ListMatches(new List<string> { "T1", "T2", "T3", "T4", "T5", "T6" }))
{
    Console.WriteLine($"{match.Day} => {match.First}-{match.Second}");
}

6个团队的输出:

0 => T1-T2
0 => T3-T6
0 => T4-T5
1 => T1-T3
1 => T4-T2
1 => T5-T6
2 => T1-T4
2 => T5-T3
2 => T6-T2
3 => T1-T5
3 => T6-T4
3 => T2-T3
4 => T1-T6
4 => T2-T5
4 => T3-T4

5个团队的输出:

0 => T1-T2
0 => T4-T5
1 => T1-T3
1 => T4-T2
2 => T1-T4
2 => T5-T3
3 => T1-T5
3 => T2-T3
4 => T2-T5
4 => T3-T4
于 2020-02-04T14:31:33.697 回答
1

我已经在 github RoundRobinTournamentSchedule上发布了我的实现 你可以找到相应的 nuget 包并在你自己的解决方案中使用它

干杯

于 2020-02-14T17:32:52.907 回答
0

那么如何计算你想要的每一天的可能组合呢

  1. 在每对中对它们进行排序,即最低数量的团队总是在任何一对中排名第一。
  2. 按每对中的第一个对每天列出的配对进行排序。
于 2009-08-18T10:49:16.830 回答
0

假设我们总是有偶数球队/球员(如果奇数,添加 BYE;对于我的情况,球队/球员按他们的评分排名,我们希望让头号种子球队/球员先与较弱的对手比赛),这是我的实现.

void CreateSchedule(int n)
{
    int[] orig = new int[n];
    for(int i=0;i<n; i++){
        orig[i] = i + 1;
    }   
    IEnumerable<int> rev = orig.Reverse();

    int len = orig.Length;
    for (int j = 0; j < len - 1; j++)
    {
        List<int> tmp = new List<int>();
        tmp.Add(orig[0]);
        tmp.AddRange(rev.Take(j).Reverse());
        if (j < len && len > 1 + j) tmp.AddRange(orig.Skip(1).Take(len - 1 - j));
        PrintMe(tmp, j + 1);
    }
}

void PrintMe(IEnumerable<int> arr, int round)
{

    Console.WriteLine("----------Round {0}----------------", round);
    int halfSize = arr.Count() / 2;

    IEnumerable<int> A = arr.Take(halfSize);
    IEnumerable<int> B = arr.Skip(halfSize).Take(halfSize).Reverse();

    var Result = A.Zip(B, (x, y) => $"{x} vs {y}");
    Console.WriteLin(Result);
}
于 2018-09-06T17:34:29.803 回答