逻辑排序的锦标赛赛程

Posted

技术标签:

【中文标题】逻辑排序的锦标赛赛程【英文标题】:Logically sorted tournament fixtures 【发布时间】:2017-09-01 09:41:04 【问题描述】:

我有一个即将举行的国际足联锦标赛,我编写了一个程序来打印出可能的比赛。问题是它没有按逻辑排序,这意味着一些玩家必须连续玩 5-6 场比赛,而另一些则必须等待 6 场比赛。我想得到以下结果:

player 1 - player 2
player 3 - player 4
player 5 - player 6
player 1 - player 3
player 2 - player 4

等等。这是我目前拥有的:

public class Fifa 

public static void main(String[] args) 
    String[] players= "Jens", "Dane", "Keppens", "Roel", "John", "Onslo", "JonasDB", "Bellon", "Sander";
    String[] players2 = "Jens", "Dane", "Keppens", "Roel", "John", "Onslo", "JonasDB", "Bellon", "Sander";


    Multimap<String, String> fixtures = LinkedHashMultimap.create();

    for(int i = 0; i < players.length; i++)
        for (int j = 0; j < players.length; j++)
            if(!players[i].equals(players2[j])) 
                if(!fixtures.containsKey(players2[j]))
                fixtures.put(players[i], players2[j]);
            
        
    

    for(Map.Entry map : fixtures.entries())
        String key = map.getKey().toString();
        Object value = map.getValue();
        System.out.println(key + " - " + value);
    

但这是打印出来的:

Jens - Dane
Jens - Keppens
Jens - Roel
Jens - John
Jens - Onslo
Jens - JonasDB
Jens - Bellon
Jens - Sander
Dane - Keppens
Dane - Roel
Dane - John
Dane - Onslo
Dane - JonasDB
Dane - Bellon
Dane - Sander
Keppens - Roel
Keppens - John
Keppens - Onslo
Keppens - JonasDB
Keppens - Bellon
Keppens - Sander
Roel - John
Roel - Onslo
Roel - JonasDB
Roel - Bellon
Roel - Sander
John - Onslo
John - JonasDB
John - Bellon
John - Sander
Onslo - JonasDB
Onslo - Bellon
Onslo - Sander
JonasDB - Bellon
JonasDB - Sander
Bellon - Sander

我使用了 Multimap,因为我需要多个具有相同值的键。

【问题讨论】:

在你的例子中,2 和 3 什么时候互相比赛?他们吗? 1-2、2-3、3-4、4-5、5-6、1-3、2-4等也可以吗?因为这可以通过遍历距离而不是索引来非常容易地完成。 他们最终会互相比赛是的。这种排序逻辑的“问题”是总会有一个玩家连续玩游戏,但它比我的实现要好。你将如何实现它? 【参考方案1】:

一种比较简单的方法是循环距离,因此我们首先输出距离为 1、2、3 等的所有匹配项。

这个的基本版本:

for(int dist = 1; dist < players.length; dist++)
for(int i = 0; i + dist < players.length; i++)
    System.out.println(players[i] + " - " + players[i+dist]);

这将按以下顺序进行匹配:(为简洁起见,按距离分组)

0 - 1, 1 - 2, 2 - 3, 3 - 4, 4 - 5, 5 - 6, 
0 - 2, 1 - 3, 2 - 4, 3 - 5, 4 - 6, 
0 - 3, 1 - 4, 2 - 5, 3 - 6, 
0 - 4, 1 - 5, 2 - 6, 
0 - 5, 1 - 6, 
0 - 6, 

如果您想避免第一行中每个人连续玩 2 场比赛的情况,您可以将其分开并按奇数和偶数分开:

for(int i = 0; i < players.length-1; i+=2)
    System.out.println(players[i] + " - " + players[i+1]);
for(int i = 1; i < players.length-1; i+=2)
    System.out.println(players[i] + " - " + players[i+1]);

for(int dist = 2; dist < players.length; dist++)
for(int i = 0; i + dist < players.length; i++)
    System.out.println(players[i] + " - " + players[i+dist]);

按此顺序进行比赛:

0 - 1, 2 - 3, 4 - 5, 
1 - 2, 3 - 4, 5 - 6, 
0 - 2, 1 - 3, 2 - 4, 3 - 5, 4 - 6, 
0 - 3, 1 - 4, 2 - 5, 3 - 6, 
0 - 4, 1 - 5, 2 - 6, 
0 - 5, 1 - 6, 
0 - 6, 

对此的一种变体是环绕并且仅循环超过一半的距离(有一种特殊情况,以避免 distance = length/2 行为偶数大小的数组重复匹配)。

for(int i = 0; i < players.length; i+=2)
    System.out.println(players[i] + " - " + players[(i+1)%players.length]);
for(int i = 1; i < players.length; i+=2)
    System.out.println(players[i] + " - " + players[(i+1)%players.length]);

for(int dist = 2; dist < (players.length+1)/2; dist++)
for(int i = 0; i < players.length; i++)
    System.out.println(players[i] + " - " + players[(i+dist)%players.length]);

if (players.length % 2 == 0)
    for(int i = 0; i < players.length/2; i++)
        System.out.println(players[i] + " - " + players[i+players.length/2]);

比赛将如下所示:

0 - 1, 2 - 3, 4 - 5, 6 - 0, 
1 - 2, 3 - 4, 5 - 6, 
0 - 2, 1 - 3, 2 - 4, 3 - 5, 4 - 6, 5 - 0, 6 - 1, 
0 - 3, 1 - 4, 2 - 5, 3 - 6, 4 - 0, 5 - 1, 6 - 2, 

【讨论】:

这正是我想要的,非常感谢!很高兴知道只有一个字符串数组是可能的,毕竟不需要哈希图!我会支持你,但我的声誉太低了。

以上是关于逻辑排序的锦标赛赛程的主要内容,如果未能解决你的问题,请参考以下文章

树形选择排序(锦标赛排序)

树形选择排序(锦标赛排序)算法详解

[golang] 数据结构-树形选择排序(锦标赛排序)

算法-排序锦标赛排序

Python | 选择排序之树形选择排序

排序算法的推导思想