策划比赛

时间:2010-05-31 07:07:54

标签: algorithm

我需要制作体育赛事的时间表。

有30支球队。每支球队必须打8场比赛。这意味着每支球队都不可能再次参加所有其他球队的比赛,但我需要避免这两支球队相互竞争不止一次。

我的想法是生成所有可能的匹配项(针对30个团队:(30*29)/2 = 435 matches)并从此列表中选择120个匹配项(每个团队匹配8个匹配项:8 * 30 / 2 = 120 matches)。

这是我遇到困难的地方:我如何选择这120场比赛?我尝试了一些简单的解决方案(列表的第一个匹配,然后是最后一个,依此类推),但它们似乎不适用于30个团队。我还尝试生成所有可能的匹配组合并找到哪一个正在工作但是有30个团队,这是太多的计算时间。

我是否可以实现现有算法?

更新

我需要制作的是一个简单的时间表,而不是消除。每支球队都有8场比赛,就这样。在一天结束时,将不会有一个获胜者。

每支球队都会有自己的赛程安排,而且这个赛程不会因为输赢而改变。规划工作一整天都是不可改变的。

更新2

起初,我不想对我的问题施加太多限制,但似乎没有任何限制(除了每个团队不会相互竞争一次),这只是一个随机挑选的问题8每支球队的比赛。

所以这里有更多细节:

在这项体育赛事期间,有6种不同的运动项目(足球,手球,篮球等)。这意味着有6个同时匹配。每15分钟开始一轮新的比赛。

每支球队必须参加8场比赛,每项运动至少一次。

这6项运动分别在三个不同的地方进行。这意味着在白天,每个团队都必须从一个地方搬到另一个地方。应尽可能减少这些举措。

球队不能连续打两场比赛。

7 个答案:

答案 0 :(得分:7)

您可以查看一些已知的匹配方法:

E.g。 Swiss Chess system

编辑:

再次阅读您的要求后 - 每个团队应该只为其他团队打一次,并且不一定要确定胜利者。似乎单个Round Robin系统可以满足您的需求。你可以将任何额外的比赛放在你需要的8之上。

答案 1 :(得分:4)

真的很简单,只需与ii-4i-3i-2i-1,{{组成团队i+1。 1}},i+2i+3。这可以使用下面的算法来完成。

i+4

<强>输出:

import java.util.*;

public class Test {

    public static void main(String[] args) {

        int TEAMS = 30, MATCHES = 8;
        int[] matchCount = new int[TEAMS];  // for a sanity check.
        List<Match> matches = new ArrayList<Match>();

        for (int team1 = 0; team1 < TEAMS; team1++)
            for (int team2 = team1 + 1; team2 <= team1 + MATCHES/2; team2++) {
                matches.add(new Match(team1, team2 % TEAMS));

                // Just for a sanity check:
                matchCount[team1]++;
                matchCount[team2 % TEAMS]++;
            }

        System.out.println(matches);

        // Sanity check:
        System.out.println(matches.size());
        System.out.println(Arrays.toString(matchCount));
    }

    static class Match {
        int team1, team2;
        public Match(int team1, int team2) {
            this.team1 = team1;
            this.team2 = team2;
        }
        public String toString() {
            return team1 + " vs " + team2;
        }
    }
}

如果您想要更随机的设置,您只需为每个团队分配1到30之间的随机数。


更新为了应对您添加的约束:让 i 匹配运动 i mod 6

答案 2 :(得分:2)

你确定你不能得到32支球队:-)?

这会让事情变得更简单 - 有一个标准的锦标赛结构,但每轮比赛的输家都会在他们自己的排行榜中出现。 我认为这最大化了在比赛期间赢得至少一场比赛的球队数量。

有30支球队,你可以让2支球队打出“友谊赛”,并在第一轮比赛中获胜。但组织变得更加复杂。

答案 3 :(得分:0)

我不知道现有的实现,但这里有一个可能的解决方案:

制作三组9支球队,并将每支球队与其他球队配对,这样每支球队都会对其他球队进行一次比赛。现在27支球队中的每支球队都打了8场比赛。

现在选择其余三支球队,每支球队一支。

修改每个团队的一些游戏:

1-2 -> 1-10, 2-10 
3-4 -> 3-10, 4-10 
5-6 -> 5-10, 6-10 
7-8 -> 7-10, 8-10

答案 4 :(得分:0)

经纪人的算法可能有用。有趣的是,我无法在网上找到好的描述,所以我会尝试解释一下这个系统。

实际上,每支球队都会向对方队伍询问比赛得分,并选出得分最高的比赛。每个团队都会重复这一过程并进行匹配。保存生成的计划并计算总分。然后使用不同的起点(即您可以随机化团队顺序),这将再次完成,如果总分更高,则选择此计划。您重复此操作,直到您找到产生高得分的计划或在预定次数的尝试之后。

总得分可以通过每个队伍的行进距离来计算,数字越小越好。显然你不会选择违反规则的比赛(太多相似类型的比赛,相同的球队再次相互比赛)。

得分可能是这样的:

  1. 如果团队的场地相同:100分(即如果两者都是200分)。
  2. 对于在场地之间旅行,根据长度确定两队的得分,即A - >。 B和B - &gt; 50分(他们在附近)A - &gt; C和C - &gt; 30分(不是那么近) B - &gt; C和C - &gt; B 0分(我们想尽可能少地旅行)。
  3. 如果球队还没有参加过这项运动:100分。
  4. 如果团队曾经参加过这项运动:50分。
  5. 当然BA的问题是为不同的参数找到好的值,所以你需要花一些时间找到它们。

答案 5 :(得分:0)

如果你想要一个简单的算法,它会产生一个时间表,在这个时间表中,团队不会多次相互竞争,这对于给定的参数来说并不难。

以下是10个团队和5个回合的示例,解决方案显示为一个数组,如果schedule [i] [j]的值为零,则团队不会一起玩,如果是一个数字则它显示了他们在哪一轮比赛。

   1  2  3  4  5  6  7  8  9  10
1 [0, 5, 0, 4, 0, 3, 0, 2, 0, 1]
2 [5, 0, 4, 0, 3, 0, 2, 0, 1, 0]
3 [0, 4, 0, 3, 0, 2, 0, 1, 0, 5]
4 [4, 0, 3, 0, 2, 0, 1, 0, 5, 0]
5 [0, 3, 0, 2, 0, 1, 0, 5, 0, 4]
6 [3, 0, 2, 0, 1, 0, 5, 0, 4, 0]
7 [0, 2, 0, 1, 0, 5, 0, 4, 0, 3]
8 [2, 0, 1, 0, 5, 0, 4, 0, 3, 0]
9 [0, 1, 0, 5, 0, 4, 0, 3, 0, 2]
10[1, 0, 5, 0, 4, 0, 3, 0, 2, 0]

所以从第一轮的表中(1,10),(2,9),(3,8),(4,7),(5,6),在第二轮比赛中,球队( 1,8),(2,7),(3,6)......等等。

要生成此表,算法相当简单,这里有一些python代码:

#!/bin/env python

def simpleNRooks(size, rounds, schedule):
    ''' Place n rooks on board so that they don't hit each other in each round,
        nor reuse the spots from previous rounds '''
    for i in range(size):
        for j in range(rounds):
            if size-j*2-i-1 < 0:
                schedule[i][2*size-j*2-i-1] = j + 1
            else:
                schedule[i][size-j*2-i-1] = j + 1

# parameters
teams = 10
matches = 5

# prepare the schedule, 0's designate free space  
schedule = [[0 for i in range(teams)] for j in range(teams)]

simpleNRooks(teams, matches, schedule)

print 'Final schedule'
for i in range(teams):
    print schedule[i]

如果您想要获得不同的数据结构(例如,轮次对的列表),您可以使用相同的原则,但更改循环。

答案 6 :(得分:0)

考虑到新约束,我正在添加一个单独的答案,因为我认为它比添加到我的旧答案更清晰。

  1. 将30支队伍分成5组,每队6支队伍:A B C D E

  2. 第一期A组和B组比赛。

  3. 然后是C&amp; D,E&amp; A,B&amp; C,D&amp; E,用于接下来的4个15分钟段。

  4. 所以在5 * 15分钟结束时:每支球队都打了两次,其中至少有一次休息时间。

    有20个周期,每个人都玩了8次。

    例如,允许B组的一支球队与A,B和B组的其他17支球队中的其他8支球队进行比赛应该很容易。 C组。

    例如,玩A队对抗B队,然后是B队对阵C队,然后是反向队列,然后是小组,然后是MOD 2,MOD 3,小组之间以及小组内。

    这样可以减少旅行时间,确保每个团队都能玩各种游戏类型。但是对于一个组解决这个问题,你可以将相同的解决方案应用于所有其他组吗?