使用模算术应该很容易实现:
更新2:(如承诺的正确算法)
public void ListMatches(List
{
if (ListTeam.Count % 2 != 0)
{
ListTeam.Add("Bye");
}
int numDays = (numTeams - 1);
int halfSize = numTeams / 2;
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]);
}
}
}
这会打印出每天的团队比赛。
让我快速解释一下算法的原理:
我注意到,由于我们除了第一个队之外旋转所有队伍,如果我们把所有队伍都放在一个数组中,除了第一个队以外,那么我们应该从该数组中读取使用基于日期的索引偏移量来获取第一个队的位置,并进行模运算以正确地包装。实际上,我们将无限重复地在两个方向上滑动我们的视图,并逐步向右(或向左)滑动。
然而,有一个问题,即我们必须以非常特定的方式对团队进行排序才能使其正常工作。否则,我们就无法得到正确的旋转。因此,我们需要以非常特殊的方式读取匹配的第二支队伍。
准备列表的正确方法如下:
永远不要将第一个队(Team#1)放入列表中。
将团队列表的后一半放在列表的前面。
将列表的前一半翻转并放入列表中(但不包括Team#1)。
现在,正确读取列表的方法如下:
对于每一天,将您正在查看的第一个索引增加1。
对于在该位置看到的第一支队伍,请将该队伍与Team#1匹配。
对于列表中的下一个团队((day + idx) % numDays),我们通常会将其与偏移量为半数团队减1的团队匹配(减1是因为我们自己处理了第一个匹配)。但是,由于我们的列表的第二半部分是准备通过翻转的方式进行的,因此我们需要在列表的反向第二半部分中匹配该偏移量。更简单的方法是观察到这等价于从列表末尾匹配相同的索引。给定当前的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.