Какой самый быстрый способ найти все возможные пары в списке? - PullRequest
3 голосов
/ 18 февраля 2011

В основном у меня есть список игроков, и я хочу объединить их в пару, чтобы каждый игрок сыграл всех по одному. Какой самый быстрый способ найти эти данные?

Ответы [ 4 ]

5 голосов
/ 18 февраля 2011

при условии, что игроки не появляются в списке дважды, двойной цикл for очень быстрый:

for (int i=0, i <= playerList.Count - 2, i++)
    for (int j=i+1, j <= playerList.Count - 1, j++)
        //add a new pairing of player i and j
2 голосов
/ 18 февраля 2011

Я собрал 2 реализации для сравнения производительности.Очень наивная версия 1 примерно на 50% медленнее, чем версия 2. Это не значит, что ничего быстрее не существует.

class Program
{
    class Player
    {
        public string Name { get; set; }

        public Player(string name)
        {
            Name = name;
        }
    }

    class Match
    {
        public readonly Player Player1;
        public readonly Player Player2;

        public Match(Player player1, Player player2)
        {
            Player1 = player1;
            Player2 = player2;
        }

        public override string ToString()
        {
            return string.Format("{0} vs. {1}", Player1.Name, Player2.Name);
        }
    }

    static readonly List<Player> _players = new List<Player>()
    {
        new Player("John"),
        new Player("Lisa"),
        new Player("Matt"),
        new Player("Dan"),
        new Player("Steve"),
        new Player("Sarah"),
        new Player("Tim")
    };

    static void Main(string[] args)
    {
        const int count = 1000000;

        {
            var v1 = V1();
            var sw = Stopwatch.StartNew();
            for (int i = 0; i < count; i++)
            {
                v1 = V1();
            }
            Console.WriteLine(v1);
            Console.WriteLine(sw.Elapsed);
        }

        {
            var v2 = V2();
            var sw = Stopwatch.StartNew();
            for (int i = 0; i < count; i++)
            {
                v2 = V2();
            }
            Console.WriteLine(v2);
            Console.WriteLine(sw.Elapsed);
        }


        Console.ReadLine();
    }

    static List<Match> V1()
    {
        var challengers = new List<Player>(_players);
        var matches = new List<Match>();
        foreach (var player in _players)
        {
            challengers.Remove(player);
            foreach (var challenger in challengers)
            {
                matches.Add(new Match(player, challenger));
            }
        }
        return matches;
    }

    static List<Match> V2()
    {
        var matches = new List<Match>();
        for (int i = 0; i < _players.Count; i++)
        {
            for (int j = i + 1; j < _players.Count; j++)
            {
                matches.Add(new Match(_players[i], _players[j]));
            }
        }
        return matches;
    }
}
2 голосов
/ 18 февраля 2011

Такое расписание турниров часто называют round-robin .В википедии также есть пример возможного алгоритма планирования .

0 голосов
/ 18 февраля 2011

Простой алгоритм «разделяй и властвуй»:

  1. Если есть только два человека: Соедините их и верните.
  2. В противном случае:

    1. Разделите группу на две группы одинакового размера.
    2. Найдите все пары в каждой группе, используя этот алгоритм рекурсивно.
    3. Соедините два списка.

      Например, [[(a,b)]] и [[(c,d)]] становится [[(a,b),(c,d)]].

    4. Найти пары поперек двух групп, вращая две группы.

      Например, [[(a,c),(b,d)],[(a,d),(b,c)]]

    5. Возврат (3) + (4)

Этот алгоритм работает за O(n^2) время, которое является оптимальным, поскольку он генерирует (n-1) раундов n/2 пар.

Длявосемь игроков вы получите 7 раундов:

[(a,b), (c,d), (e,f), (g,h)]
[(a,c), (b,d), (e,g), (f,h)]
[(a,d), (b,c), (e,h), (f,g)]
[(a,e), (b,f), (c,g), (e,h)]
[(a,f), (b,g), (c,h), (e,e)]
[(a,g), (b,h), (c,e), (e,f)]
[(a,h), (b,e), (c,f), (e,g)]
...