分发比赛'锦标赛友好'

时间:2015-12-19 02:32:52

标签: c# distribution evenly matchmaking

假设我有四支球队,ABCD,我想创建比赛,以便球队必须均匀地进行比赛:

不希望

  • A vs B
  • A vs C
  • A vs D
  • B vs C
  • B vs D
  • C vs D

期望

  • A vs B
  • C vs D
  • B vs C
  • A vs D
  • A vs C
  • B vs D

另一种表达方式:我希望球队尽可能少地进行比赛 目标语言是C#,但我可以轻松翻译。

编辑:快速旁注,它可以超过4个团队!

2 个答案:

答案 0 :(得分:1)

我认为您可以按照以下方式实现您的需求。如果您有 n 个团队,团队之间的所有可能匹配都可以用Kn Complete graph来表示。

我想出你想要的排序的方法是从该图表中一次一个地取出(移除)边缘,总是试图找到与之前不匹配的团队相匹配的边缘。更进一步,我认为这种方法(有一点变化)可以用来产生最大化并发比赛的最佳方式,如果你每次获得优势,你就会选择一支在大部分时间都没有参加比赛的球队。

为简单起见,我们假设团队的整数范围为0到 n -1。该图可以简单地用布尔矩阵表示。要选择与大部分时间没有比赛的球队的比赛,您可以跟踪每支球队的最后一次比赛。对于n个小组,您总共有n*(n-1)/2个匹配。

IEnumerable<Tuple<int,int>> GenerateMatches(int n) {
    bool[,] pendingMatches = new bool[n,n];
    for (int i = 0; i < n; i++) {
        for (int j = 0; j < i; j++)
            pendingMatches[i,j] = true;
    }

    int[] lastPlayed = new int[n];
    int totalMatches = n*(n-1)/2;
    for (int m = 1; m <= totalMatches; m++) {
        Tuple<int, int> t = null;
        int longestPlayed = -1;
        for (int i = 0; i < n; i++) {
            for (int j = 0; j < i; j++) {
                if (pendingMatches[i,j]) {
                    int moreRecentlyPlayed = Math.Max(lastPlayed[i], lastPlayed[j]);
                    int timeSinceLastPlay = m - moreRecentlyPlayed;
                    if (timeSinceLastPlay > longestPlayed) {
                        longestPlayed = timeSinceLastPlay;
                        t = Tuple.Create(i,j);
                    }
                }
            }
        }
        lastPlayed[t.Item1] = lastPlayed[t.Item2] = m;
        pendingMatches[t.Item1, t.Item2] = false;
        yield return t;
    }
}

选择下一场比赛的部分是两个最嵌套的比赛。如果在更新lastPlayed数组后使用某种优先级队列来调整涉及最后一个拾取边的团队的边缘优先级,则可以提高该部分的复杂性。

希望有所帮助。

答案 1 :(得分:1)

解决此问题的一种方法是通过以下步骤:

  1. 创建一个包含匹配组合总数的集合。
  2. 创建一个与步骤1中的集合长度相同的新集合。
  3. 完成步骤1中的项目,在步骤2中添加相同的项目,条件是要添加的下一个项目应该具有最大添加项目之间的最大差异。
  4. 一些示例代码:

    // Just a container to conveniently hold a match between two teams
    public class Match
    {
        public Match(string teamOne, string teamTwo)
        {
            TeamOne = teamOne;
            TeamTwo = teamTwo;
        }
    
        public string TeamOne { get; private set; }
    
        public string TeamTwo { get; private set; }
    
        public override string ToString()
        {
            return String.Format("{0} vs {1}", TeamOne, TeamTwo);
        }
    }
    
    public class MatchMaking
    {
        public MatchMaking()
        {
            Teams = new List<string> { "A", "B", "C", "D", "E" };
        }
    
        public IList<string> Teams { get; private set; }
    
        public IList<Match> GetMatches()
        {
            var unorderedMatches = GetUnorderedMatches();
    
            // The list that we will eventually return
            var orderedMatches = new List<Match>();
    
            // Track the most recently added match
            Match lastAdded = null;
    
            // Loop through the unordered matches
            // Add items to the ordered matches
            // Add the one that is most different from the last added match
            for (var i = 0; i < unorderedMatches.Count; i++)
            {
                if (lastAdded == null)
                {
                    lastAdded = unorderedMatches[i];
                    orderedMatches.Add(unorderedMatches[i]);
                    unorderedMatches[i] = null;
                    continue;
                }
    
                var remainingMatches = unorderedMatches.Where(m => m != null);
    
                // Get the match which is the most different from the last added match
                // We do this by examining all of the unadded matches and getting the maximum difference
                Match mostDifferentFromLastAdded = null;
                int greatestDifference = 0;
                foreach (var match in remainingMatches)
                {
                    var difference = GetDifference(lastAdded, match);
                    if (difference > greatestDifference)
                    {
                        greatestDifference = difference;
                        mostDifferentFromLastAdded = match;
                    }
    
                    if (difference == 2)
                    {
                        break;
                    }
                }
    
                // Add the most different match
                var index = unorderedMatches.ToList().IndexOf(mostDifferentFromLastAdded);
                lastAdded = unorderedMatches[index];
                orderedMatches.Add(unorderedMatches[index]);
                unorderedMatches[index] = null;
            }
    
            return orderedMatches;
        }
    
        // Create a list containing the total match combinations with an arbitrary order
        private List<Match> GetUnorderedMatches()
        {
            var totalNumberOfCombinations = AdditionFactorial(Teams.Count - 1);
    
            var unorderedMatches = new List<Match>(totalNumberOfCombinations);
            for (int i = 0; i < Teams.Count; i++)
            {
                for (int j = 0; j < Teams.Count; j++)
                {
                    if (j <= i) continue;
    
                    unorderedMatches.Add(new Match(Teams[i], Teams[j]));
                }
            }
            return unorderedMatches;
        }
    
        // Get the difference between two matches
        // 0 - no difference, 1 - only one team different, 2 - both teams different
        private int GetDifference(Match matchOne, Match matchTwo)
        {
            var matchOneTeams = new HashSet<string> { matchOne.TeamOne, matchOne.TeamTwo };
            var matchTwoTeams = new HashSet<string> { matchTwo.TeamOne, matchTwo.TeamTwo };
            var intersection = matchOneTeams.Intersect(matchTwoTeams);
    
            return (intersection.Count() - 2) * -1;
        }
    
        // Just a helper to get the total number of match combinations
        private int AdditionFactorial(int seed)
        {
            int result = 0;
    
            for (int i = seed; i > 0; i--)
            {
                result += i;
            }
    
            return result;
        }
    }
    
    public class Program
    {
        private static void Main(string[] args)
        {
            var matchMaking = new MatchMaking();
    
            foreach (var match in matchMaking.GetMatches())
            {
                Console.WriteLine(match);
            }
        }
    }