我正在制作一个HTML / JS驱动的单/双消除支架Web应用程序。我正在努力弄清楚如何从种子队/球员名单中分配第一轮比赛。例如,在8名球员的支架中,第一轮比赛是:
1V8 4V5 2V7 3V6
在更通用的术语中,种子可以被认为是一个数组(因为我通过弹出一个数组来指定团队匹配): 1,2,3,4,5,6,7,8-
需要分类到: 1,8,4,5,2,7,3,6
为了澄清,较高的种子需要在排序的数组中具有它们之间的最大距离,这使得在没有扰乱的括号中,较低的种子首先被淘汰并且与高种子的匹配尽可能晚地发生。实际上,想想一个网球锦标赛,你想要阻止16或32等支架的前4名球员互相比赛直到半决赛。因此, 16 种子支架的正确数组输出为:
1,16,8,9,4,13,5,12,2,15,7,10,3,14,6,11
转换为以下第一轮比赛:
1v16 8v9 4v13 5v12 2v15 7v10 3v14 6v11
感谢Matt Ball提供8种子支架的正确算法
答案 0 :(得分:8)
从顶部和底部匹配球员的想法是正确的但不完全。这样做一次对第一轮很有用:
while (seeds.length)
{
firstRound.push(seeds.shift());
firstRound.push(seeds.pop());
}
1, 2, 3, 4, 5, 6, 7, 8 => 1, 8, 2, 7, 3, 6, 4, 5
...但是在第二轮中,种子1遇到种子2和3遇到4.我们需要为每轮进行第一次/最后一次洗牌。第一次,我们将每个元素单独移动。第二次,我们移动每个 PAIR 元素。我们第三次移动四个小组等,直到我们的小组大小为seeds.length/2
。像这样:
// this is ruby, aka javascript psuedo-code :)
bracket_list = seeds.clone
slice = 1
while slice < bracket_list.length/2
temp = bracket_list
bracket_list = []
while temp.length > 0
bracket_list.concat temp.slice!(0, slice) # n from the beginning
bracket_list.concat temp.slice!(-slice, slice) # n from the end
end
slice *= 2
end
return bracket_list
这是在进行迭代时数组的样子(括号表示增加的组大小):
1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16
(1, 16), (2, 15), (3, 14), (4, 13), (5, 12), (6, 11), (7, 10), (8, 9)
(1, 16, 8, 9), (2, 15, 7, 10), (3, 14, 6, 11), (4, 13, 5, 12)
(1, 16, 8, 9, 4, 13, 5, 12), (2, 15, 7, 10, 3, 14, 6, 11)
所以现在,在排名最后的8名球员之后,我们留下了1, 8, 4, 5, 2, 7, 3, 6
。在底部4被淘汰后,我们有1, 4, 2, 3
,而在最后一轮只有1, 2
。
如果不能画出一个括号,很难解释这一点......如果我能为你澄清一些内容,请告诉我。
答案 1 :(得分:2)
这可能不如使用自定义sort
函数的 @ alex的回答那样有效,但肯定更容易编写和理解:
// This algorithm assumes that seeds.length is an even number
var seeds = [1, 2, 3, 4, 5, 6, 7, 8],
firstRound = [];
while (seeds.length)
{
firstRound.push(seeds.shift());
firstRound.push(seeds.pop());
}
// seeds is now empty
// firstRound is now [1, 8, 2, 7, 3, 6, 4, 5]
实际上,我只想到了一个更快的算法(就地“排序”,需要O(n)
次):
// Also assumes that seeds.length is an even number
var seeds = [1, 2, 3, 4, 5, 6, 7, 8],
numSeeds = seeds.length,
stop = numSeeds >> 1,
temp;
for (var i=1; i<stop; i=i+2)
{
temp = seeds[i];
seeds[i] = seeds[numSeeds-i];
seeds[numSeeds-i] = temp;
}
// seeds is now [1, 8, 3, 6, 5, 4, 7, 2]
请注意,这些算法都不会像OP中那样生成完全相同的 order 对,但它们都会生成相同的 set 对:
(1,8)
(2,7)
(3,6)
(4,5)
答案 2 :(得分:2)
我提出了一个解决方案,但它不在“排序数组”的范围之内。
(javascript)代码位于http://jsbin.com/ukomo5/2/edit。
在基本术语中,算法假设括号中不会出现扰乱,因此种子1和2 应该在最后一轮中相遇。它遍历每轮中的每个种子(从预先计算的总决赛开始,向后工作),计算当前种子(在迭代中)赢得的前一轮中的未知种子。这可以做到,因为给定种子和数字,你可以弄清楚其他种子应该是什么:
其他种子=圆形+ 1中的种子数 - 已知种子
为了说明,在半决赛中:
半决赛1(已知种子为1):其他种子= 4 + 1 - 1 = 4
半决赛2(已知种子为2):其他种子= 4 + 1 - 2 = 3
当我看到我画的“无心烦”支架时,我才注意到这种模式。
在最后的迭代(即第1轮)中,所有种子及其位置都是已知的,准备分配给匹配。正确的排序数组如下:
1,16,8,9,4,13,5,12,2,15,7,10,3,14,6,11
再次感谢Matt Ball提出了一个小括号的正确解决方案(如果没有详细的上下文,很难说明问题和所需的解决方案,我在最初的问题中没有做到这一点)。
如果有人有其他解决方案或更优雅的解决方案,请告诉我们!
答案 3 :(得分:1)
这是我开发的算法。第1步是绘制一个包含尽可能多的行的表(四舍五入为2的幂),并根据需要绘制尽可能多的列来表示二进制中的团队数量。说,有8支球队。该表最初看起来像这样(点表示水平单元格边框):
。 。 。 | | | | 。 。 。 | | | | 。 。 。 | | | | 。 。 。 | | | | 。 。 。 | | | | 。 。 。 | | | | 。 。 。 | | | | 。 。 。 | | | | 。 。
列从左侧按升序编号。对于每列,每隔2 ^(列号)行放一个星号。也就是说,第1列中的每第2行,第2列中的每第4行等等。
。 。 。 | | | | 。 。 。 | | | | *。 。 | | | | 。 。 。 | | | | * *。 | | | | 。 。 。 | | | | *。 。 | | | | 。 。 。 | | | |
从第1行的每列中的0开始。此后,对于每列中的连续行,从0-1和1-0切换,除非该行中有星号。这是结果:
。 。 。 | 0 | 0 | 0 | 。 。 。 | 1 | 1 | 1 | *。 。 | 1 | 0 | 0 | 。 。 。 | 0 | 1 | 1 | * *。 | 0 | 1 | 0 | 。 。 。 | 1 | 0 | 1 | *。 。 | 1 | 1 | 0 | 。 。 。 | 0 | 0 | 1 |
最后一步是评估将0和1的字符串作为二进制数处理的每一行。这将导致0-7的值。每个添加1会产生1-8的值。这些对应于种子。
。 。 。 | 0 | 0 | 0 | + 1 = 1 。 。 。 | 1 | 1 | 1 | + 1 = 8 *。 。 | 1 | 0 | 0 | + 1 = 5 。 。 。 | 0 | 1 | 1 | + 1 = 4 * *。 | 0 | 1 | 0 | + 1 = 3 。 。 。 | 1 | 0 | 1 | + 1 = 6 *。 。 | 1 | 1 | 0 | + 1 = 7 。 。 。 | 0 | 0 | 1 | + 1 = 2
每对种子都是按顺序播放的比赛。即。 1-8,5-4,3-6和7-2。这可以扩展到任何数量的种子。当由于条目的数量小于2的幂而要插入字节时,它们采用最高的种子值。例如。如果只有28个条目,那么byes将分配给29,30,31和32的位置。
答案 4 :(得分:0)
我用PHP编写了一个解决方案(参见https://stackoverflow.com/a/45566890/760777)。 这是javascript版本。
它会将所有种子返回到正确的位置。匹配与他的示例相同,但在更漂亮的顺序中,种子1和种子编号8位于模式的外部(正如您在网球锦标赛中看到的那样)。
如果没有沮丧(意味着较高种子的球员总是从低种子球员中获胜),你将在决赛中以种子1和种子2结束。
它实际上做了两件事:
显示正确的顺序(这是将byes放在正确位置的要求)
它会在正确的位置填写(如果需要)
关于单个消除括号应该是什么样子的完美解释:http://blog.playdriven.com/2011/articles/the-not-so-simple-single-elimination-advantage-seeding/
8名参与者的代码示例:
var NUMBER_OF_PARTICIPANTS = 8; // Set the number of participants
if (!String.prototype.format) {
String.prototype.format = function() {
var args = arguments;
return this.replace(/{(\d+)}/g, function(match, number) {
return typeof args[number] != 'undefined' ? args[number] : match;
});
};
}
var participants = Array.from({length: NUMBER_OF_PARTICIPANTS}, (v, k) => k + 1) ;
var bracket = getBracket(participants);
console.log(bracket);
function getBracket(participants)
{
var participantsCount = participants.length;
var rounds = Math.ceil(Math.log(participantsCount)/Math.log(2));
var bracketSize = Math.pow(2, rounds);
var requiredByes = bracketSize - participantsCount;
console.log("Number of participants: {0}".format(participantsCount));
console.log("Number of rounds: {0}".format(rounds));
console.log("Bracket size: {0}".format(bracketSize));
console.log("Required number of byes: {0}".format(requiredByes));
if(participantsCount < 2) {
return [];
}
var matches = [[1,2]];
for(var round = 1; round < rounds; round++) {
var roundMatches = [];
var sum = Math.pow(2, round + 1) + 1;
for(var i = 0; i < matches.length; i++) {
var home = changeIntoBye(matches[i][0], participantsCount);
var away = changeIntoBye(sum - matches[i][0], participantsCount);
roundMatches.push([home, away]);
home = changeIntoBye(sum - matches[i][1], participantsCount);
away = changeIntoBye(matches[i][1], participantsCount);
roundMatches.push([home, away]);
}
matches = roundMatches;
}
return matches;
}
function changeIntoBye(seed, participantsCount)
{
//return seed <= participantsCount ? seed : '{0} (= bye)'.format(seed);
return seed <= participantsCount ? seed : null;
}
将NUMBER_OF_PARTICIPANTS从8更改为6以获得两个字节。
祝你好运。 RWC答案 5 :(得分:0)
Cliff的算法here给我留下了深刻的印象。我认为这非常聪明。这是我用ruby编写的一个简单实现。 BYE返回为-1。
def seed(n)
rounded_n = next_power_of_two(n)
nbr_bits_required=rounded_n.to_s(2).length-1
binary_seeds = Array.new(rounded_n) {Array.new(nbr_bits_required)}
binary_seeds[0]=Array.new(nbr_bits_required){0}
nbr_bits_required.times do |col|
1.upto(rounded_n-1) do |row|
if row % (2**(col+1)) == 0
#asterisk in the previous row, don't inverse the bit
binary_seeds[row][col] = binary_seeds[row-1][col]
else
#no asterisk in the previous row, inverse the bit
binary_seeds[row][col] = binary_seeds[row-1][col] == 0 ? 1 : 0
end
end
end
#output the result in decimal format
binary_seeds.collect {|bs| s=(bs.join("")).to_i(2)+1; s>n ? -1 : s}
end
def next_power_of_two(n)
k = 1
k*=2 while k<n
k
end
测试一下:
seed(8)
=> [1, 8, 5, 4, 3, 6, 7, 2]
seed(6)
=> [1, -1, 5, 4, 3, 6, -1, 2]