C#中的循环竞赛算法

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

那我想输出;

第1天:第1队与第2队; 第3队与第4队; Team 5vs Team 6;

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

直到锦标赛结束;

这是我到目前为止所获得的代码,但是当arrays的其余部分旋转时,我很难让第一个团队修复……:

static void Main(string[] args) { string[] ListTeam = new string[] {"Equipe1", "Equipe2", "Equipe3", "Equipe4", "Equipe5", "Equipe6"}; IList ListMatch = new List(); it NumberOfDays = (ListTeam.Count()-1); int y = 2; for (int i = 1; i 0 ; y--) { Console.WriteLine(ListTeam[y].ToString() + " VS " + ListTeam[y+1].ToString()); y++; } } } 

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

这应该很容易使用模块化算法:

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

 public void ListMatches(List ListTeam) { if (ListTeam.Count % 2 != 0) { ListTeam.Add("Bye"); } int numDays = (numTeams - 1); int halfSize = numTeams / 2; List teams = new List(); 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]); } } } 

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

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

我注意到,因为除了第一个团队之外我们正在轮换所有团队,如果我们将所有团队放在除第一个团队之外的数组中,那么我们应该根据当天使用索引偏移来读取该数组中的第一个团队模数运算正确包裹。 在实践中,我们将该数组视为在两个方向上无限重复,我们将逐渐向右(或向左)滑动我们的视图。

然而,有一个障碍,那就是我们必须以非常特殊的方式为团队订购才能使其正常工作。 否则,我们无法获得正确的旋转。 因此,我们需要以非常特殊的方式阅读匹配的第二个团队。

准备列表的正确方法如下:

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

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

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

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

我甚至没有看到你在哪里试图旋转arrays。 排列看起来像:1 – > 2 – > 3 – > 4 … – > n / 2 – 1 – > n – 1 – > n – 2 – > n – 3 – > … – > n / 2 – > 1(0保持固定)。 您可以在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 temp = new List(); List teams = new List(); 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个方法并传递和整数(Day),就像我在2个注释行中所做的那样,来分隔代码。

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

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

每天i = 1 .. n:

  • 选择任意两个直接连接的未标记顶点,并用i标记它们之间的边缘。 标记两个顶点。
  • 重复,直到标记所有顶点。
  • 输出标记的边缘(即team1 vs team2,team3 vs team4等)
  • 从图形中删除带标签的边缘,并将所有顶点重置为未标记。

如何计算您想要的每一天的可能组合

  1. 在每对中排序它们,即最低数量的团队总是在任何一对中排在第一位。
  2. 按每对中的第一个对每天列出的配对进行排序。

假设我们总是拥有偶数球队/球员(如果奇怪的话,加上BYE;对于我的情况,球队/球员按他们的等级排名,我们希望让顶级种子队/球员先打弱对手),这是我的实施。

 void CreateSchedule(int n) { int[] orig = new int[n]; for(int i=0;i rev = orig.Reverse(); int len = orig.Length; for (int j = 0; j < len - 1; j++) { List tmp = new List(); 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 arr, int round) { Console.WriteLine("----------Round {0}----------------", round); int halfSize = arr.Count() / 2; IEnumerable A = arr.Take(halfSize); IEnumerable B = arr.Skip(halfSize).Take(halfSize).Reverse(); var Result = A.Zip(B, (x, y) => $"{x} vs {y}"); Console.WriteLin(Result); }