C#单循环赛(Round-robin)生成器问题:配对数量不足
单循环赛(Round-robin)配对生成器问题排查与修复(C#)
你的C#单循环赛生成器存在配对不完整的问题:12位选手应生成66组唯一配对(11轮,每轮6组),但当前代码仅生成50组,且前3轮后每轮只能生成4组配对。
问题根源
当前代码采用嵌套循环暴力遍历选手配对的方式,逻辑上存在核心缺陷:
- 固定的遍历顺序会导致后续轮次中部分选手的可用配对被提前耗尽,无法凑齐每轮所需的全部配对
- 未遵循单循环赛的标准轮转规则,暴力匹配容易出现「配对断层」,无法覆盖所有可能的选手组合
修复方案:使用标准单循环赛轮转算法
单循环赛有成熟的轮转生成规则,能保证每轮所有选手都参与配对(奇数时加入轮空选手0),且所有选手仅交手一次。以下是修改后的完整代码:
修改后的Button点击事件代码
private void button_G_Click(object sender, EventArgs e) { int originalPlayerCount = (int)numericUpDown1.Value; bool hasBye = originalPlayerCount % 2 != 0; int playerCount = hasBye ? originalPlayerCount + 1 : originalPlayerCount; int totalRounds = playerCount - 1; int pairsPerRound = playerCount / 2; List<Pair> allPairs = new List<Pair>(); List<int> players = Enumerable.Range(hasBye ? 0 : 1, playerCount).ToList(); for (int round = 0; round < totalRounds; round++) { List<Pair> roundPairs = new List<Pair>(); // 生成当前轮的配对 for (int i = 0; i < pairsPerRound; i++) { int p1 = players[i]; int p2 = players[playerCount - 1 - i]; // 跳过轮空选手自己配对的情况(仅奇数人数时出现) if (p1 != p2) { roundPairs.Add(new Pair(p1, p2)); } } // 记录本轮配对并添加到列表控件 int gameNum = 0; foreach (var pair in roundPairs) { gameNum++; allPairs.Add(pair); listBox1.Items.Add($"{allPairs.Count}. Round {round + 1}, game {gameNum}: [player {pair.Player1}] vs [player {pair.Player2}]"); } listBox2.Items.Add($"Round {round + 1}: {roundPairs.Count} pairs"); // 执行轮转操作:固定第一个选手,其余选手顺时针轮转 if (playerCount > 2) { int lastPlayer = players[playerCount - 1]; players.RemoveAt(playerCount - 1); players.Insert(1, lastPlayer); } } // 输出每位选手的对手列表 Console.WriteLine("Show each player matchup"); int startPlayer = hasBye ? 0 : 1; foreach (var player in Enumerable.Range(startPlayer, originalPlayerCount)) { var opponents = allPairs .Where(x => x.Player1 == player || x.Player2 == player) .Select(x => x.Player1 == player ? x.Player2 : x.Player1) .OrderBy(x => x); Console.WriteLine($"Player: {player.ToString().PadLeft(2)}: {string.Join(", ", opponents.Select(x => x.ToString().PadLeft(2)))}"); } }
Pair类保持不变
public class Pair { public int Player1 { get; set; } = -1; public int Player2 { get; set; } = -1; public Pair(int p1, int p2) { Player1 = p1; Player2 = p2; } }
代码说明
- 轮转规则:固定第一个选手,其余选手每轮顺时针移动一个位置,确保所有选手能遍历到其他所有对手
- 轮空处理:当选手数为奇数时,自动添加选手0作为轮空选手,该选手在每轮中与一位真实选手配对(代表该真实选手轮空获胜)
- 配对完整性:12位选手会生成11轮,每轮6组配对,总计66组唯一配对,完全符合单循环赛要求
验证结果
运行修改后的代码,12位选手的输出会显示每位选手都与其他11位选手各交手一次,总配对数为66,每轮都能生成完整的6组配对。
内容的提问来源于stack exchange,提问作者Stanislav Vladev
相关产品推荐
相关产品推荐

