Algorithm 锦标赛括号放置算法

Algorithm 锦标赛括号放置算法,algorithm,language-agnostic,brackets,tournament,Algorithm,Language Agnostic,Brackets,Tournament,给定一个对手种子列表(例如种子1到16),我正在尝试编写一个算法,该算法将导致在该轮中顶部种子扮演最低种子,第二个种子扮演第二个最低种子,等等 将1号和16号、2号和15号等分为“比赛”是相当容易的,但我还需要确保较高的种子将在随后的几轮中扮演较低的种子 放置正确的支架示例: 1 vs 16 1 vs 8 8 vs 9 1 vs 4 4 vs 13 4 vs 5 5 vs 12

给定一个对手种子列表(例如种子1到16),我正在尝试编写一个算法,该算法将导致在该轮中顶部种子扮演最低种子,第二个种子扮演第二个最低种子,等等

将1号和16号、2号和15号等分为“比赛”是相当容易的,但我还需要确保较高的种子将在随后的几轮中扮演较低的种子

放置正确的支架示例:

1 vs 16 1 vs 8 8 vs 9 1 vs 4 4 vs 13 4 vs 5 5 vs 12 1 vs 2 2 vs 15 2 vs 7 7 vs 10 2 vs 3 3 vs 14 3 vs 6 6 vs 11 1比16 1比8 8比9 1对4 4比13 4比5 5比12 1对2 2比15 2对7 7比10 2对3 3比14 3比6 6比11 正如你所见,种子1和种子2只在决赛中相遇。

  • 在每一轮中,根据播种标准对团队进行排序
  • (如果一轮有n个队)第i个位置的队与n-i+1队比赛

根据您的假设,1号和2号选手将参加决赛,1-4号选手将参加半决赛,1-8号选手将参加四分之一决赛,依此类推,因此您可以按照阿卡什的建议,从决赛向后递归构建锦标赛。把锦标赛想象成一棵树,它的根是最后一棵树

在根节点中,玩家是{1,2}

要递归地将树扩展到下一个级别,请逐个获取树底层的所有节点,并为每个节点创建两个子节点,然后将原始节点的一个播放机放置到创建的每个子节点上。然后添加下一层玩家并将其映射到游戏中,以便最差的新添加玩家与最好的现有玩家进行游戏,依此类推

这里是算法的第一轮:

 {1,2}  --- create next layer

       {1, _}
      /         --- now fill the empty slots
 {1,2}
      \{2, _}

       {1, 4}   --- the slots filled in reverse order
      /         
 {1,2}
      \{2, 3}   --- create next layer again


             /{1, _}
       {1, 4}
      /      \{4, _}
 {1,2}                  --- again fill
      \      /{2, _}
       {2, 3}
             \{3, _}

             /{1, 8}
       {1, 4}
      /      \{4, 5}    --- ... and so on
 {1,2}
      \      /{2, 7}
       {2, 3}
             \{3, 6}

如您所见,它生成的树与您发布的树相同。

我提出了以下算法。它可能不是超高效的,但我不认为它真的需要。它是用PHP编写的


此JavaScript返回一个数组,其中每个偶数索引播放下一个奇数索引

function seeding(numPlayers){
  var rounds = Math.log(numPlayers)/Math.log(2)-1;
  var pls = [1,2];
  for(var i=0;i<rounds;i++){
    pls = nextLayer(pls);
  }
  return pls;
  function nextLayer(pls){
    var out=[];
    var length = pls.length*2+1;
    pls.forEach(function(d){
      out.push(d);
      out.push(length-d);
    });
    return out;
  }
}

> seeding(2)
[1, 2]
> seeding(4)
[1, 4, 2, 3]
> seeding(8)
[1, 8, 4, 5, 2, 7, 3, 6]
> seeding(16)
[1, 16, 8, 9, 4, 13, 5, 12, 2, 15, 7, 10, 3, 14, 6, 11]
函数种子设定(numPlayers){
var rounds=Math.log(numPlayers)/Math.log(2)-1;
var-pls=[1,2];
对于(var i=0;i)(2)
[1, 2]
>播种(4)
[1, 4, 2, 3]
>播种(8)
[1, 8, 4, 5, 2, 7, 3, 6]
>播种(16)
[1, 16, 8, 9, 4, 13, 5, 12, 2, 15, 7, 10, 3, 14, 6, 11]
#python中有一个-它使用嵌套列表理解来简洁:
从数学导入日志,ceil
def种子(n):
“”“以标准比赛种子顺序返回n的列表
请注意,n不必是2的幂-“是”返回为零
"""
ol=[1]
对于范围内的i(cel(log(n)/log(2)):
l=2*len(ol)+1

ol=[e if e由于在搜索主题时会出现这种情况,并且无法找到解决问题的另一个答案,并且无法将种子按“更漂亮”的顺序排列,因此我将添加darkangel提供的PHP代码版本。我还添加了向更高种子玩家表示“是”的可能性

这是在OO环境中编写的,因此参与者的数量在$This->finalinters中,通过的数量在$This->yes中。我只测试了没有通过和两个通过的代码

  public function getBracket() {
      $players = range(1, $this->finalists);
      for ($i = 0; $i < log($this->finalists / 2, 2); $i++) {
        $out = array();
        $reverse = false;
        foreach ($players as $player) {
          $splice = pow(2, $i);
          if ($reverse) {
            $out = array_merge($out, array_splice($players, -$splice));
            $out = array_merge($out, array_splice($players, 0, $splice));
            $reverse = false;
          } else {
            $out = array_merge($out, array_splice($players, 0, $splice));
            $out = array_merge($out, array_splice($players, -$splice));
            $reverse = true;
          }
        }
        $players = $out;
      }
      if ($this->byes) {
        for ($i = 0; $i < $this->byes; $i++ ) {
          for ($j = (($this->finalists / pow(2, $i)) - 1); $j > 0; $j--) {
            $newPlace = ($this->finalists / pow(2, $i)) - 1;
            if ($players[$j] > ($this->finalists / (pow(2 ,($i + 1))))) {
              $player = $players[$j];
              unset($players[$j]);
              array_splice($players, $newPlace, 0, $player);
            }
          }
        }
        for ($i = 0; $i < $this->finalists / (pow(2, $this->byes)); $i++ ) {
          $swap[] = $players[$i];
        }
        for ($i = 0; $i < $this->finalists /(pow(2, $this->byes)); $i++ ) {
          $players[$i] = $swap[count($swap) - 1 - $i];
        }
        return array_reverse($players);
      }
      return $players;
    }
公共函数getBracket(){
$players=范围(1,$this->决赛选手);
对于($i=0;$ifinalists/2,2);$i++){
$out=array();
$reverse=false;
foreach($player作为$player){
$splice=pow(2$i);
如果($反向){
$out=阵列合并($out,阵列拼接($players,$splice));
$out=阵列合并($out,阵列拼接($players,0,$splice));
$reverse=false;
}否则{
$out=阵列合并($out,阵列拼接($players,0,$splice));
$out=阵列合并($out,阵列拼接($players,$splice));
$reverse=true;
}
}
$players=$out;
}
如果($this->yes){
对于($i=0;$i<$this->yes;$i++){
对于($j=($this->决赛选手/pow(2$i))-1);$j>0;$j--){
$newPlace=($this->决赛选手/pow(2$i))-1;
如果($players[$j]>($this->入围者/(pow(2,($i+1‘‘‘)')){
$player=$players[$j];
未设置($players[$j]);
阵列拼接($players,$newPlace,0,$player);
}
}
}
对于($i=0;$i<$this->入围者/(pow(2,$this->是));$i++){
$swap[]=$players[$i];
}
对于($i=0;$i<$this->入围者/(pow(2,$this->是));$i++){
$players[$i]=$swap[计数($swap)-1-$i];
}
返回数组\u反向($players);
}
返回$players;
}

对于JavaScript代码,请使用以下两个函数之一。前者体现命令式风格,速度更快。后者是递归的,更简洁,但只适用于相对较少的团队(>1,m=1;i>=1;i>=1,m=(m 0;j-=i){ arr[j]=m-arr[j-=i] } } 返回arr }
在这里,您可以通过镜像已占用的位置来逐个填充这些位置。例如,第一个种子团队(即编号为
0
)位于最顶端的位置。第二个团队(
1
)位于括号另一半的相对位置。第三个团队(
2
)将
1
镜像到括号的一半,依此类推。尽管存在嵌套循环,但该算法的时间复杂度取决于团队的数量

以下是递归方法:

//函数式样式
常量foo=n=>
n===1?[0]:foo(n>>1).reduce((p,c)=>[…p,c,n-c-1],)
基本上,您可以执行与上一个函数相同的镜像,但会以递归方式执行:

  • 对于
    n=1
    团队,它只是
    [0]

  • 对于
    n=2
    团队,将此函数应用于参数
    n-1
    (即,
    1
    )&get
    [0]
    。然后通过插入镜像 元素
      public function getBracket() {
          $players = range(1, $this->finalists);
          for ($i = 0; $i < log($this->finalists / 2, 2); $i++) {
            $out = array();
            $reverse = false;
            foreach ($players as $player) {
              $splice = pow(2, $i);
              if ($reverse) {
                $out = array_merge($out, array_splice($players, -$splice));
                $out = array_merge($out, array_splice($players, 0, $splice));
                $reverse = false;
              } else {
                $out = array_merge($out, array_splice($players, 0, $splice));
                $out = array_merge($out, array_splice($players, -$splice));
                $reverse = true;
              }
            }
            $players = $out;
          }
          if ($this->byes) {
            for ($i = 0; $i < $this->byes; $i++ ) {
              for ($j = (($this->finalists / pow(2, $i)) - 1); $j > 0; $j--) {
                $newPlace = ($this->finalists / pow(2, $i)) - 1;
                if ($players[$j] > ($this->finalists / (pow(2 ,($i + 1))))) {
                  $player = $players[$j];
                  unset($players[$j]);
                  array_splice($players, $newPlace, 0, $player);
                }
              }
            }
            for ($i = 0; $i < $this->finalists / (pow(2, $this->byes)); $i++ ) {
              $swap[] = $players[$i];
            }
            for ($i = 0; $i < $this->finalists /(pow(2, $this->byes)); $i++ ) {
              $players[$i] = $swap[count($swap) - 1 - $i];
            }
            return array_reverse($players);
          }
          return $players;
        }
    
    <?php
    
    define('NUMBER_OF_PARTICIPANTS', 16);
    
    $participants = range(1,NUMBER_OF_PARTICIPANTS);
    $bracket = getBracket($participants);
    var_dump($bracket);
    
    function getBracket($participants)
    {
        $participantsCount = count($participants);  
        $rounds = ceil(log($participantsCount)/log(2));
        $bracketSize = pow(2, $rounds);
        $requiredByes = $bracketSize - $participantsCount;
    
        echo sprintf('Number of participants: %d<br/>%s', $participantsCount, PHP_EOL);
        echo sprintf('Number of rounds: %d<br/>%s', $rounds, PHP_EOL);
        echo sprintf('Bracket size: %d<br/>%s', $bracketSize, PHP_EOL);
        echo sprintf('Required number of byes: %d<br/>%s', $requiredByes, PHP_EOL);    
    
        if($participantsCount < 2)
        {
            return array();
        }
    
        $matches = array(array(1,2));
    
        for($round=1; $round < $rounds; $round++)
        {
            $roundMatches = array();
            $sum = pow(2, $round + 1) + 1;
            foreach($matches as $match)
            {
                $home = changeIntoBye($match[0], $participantsCount);
                $away = changeIntoBye($sum - $match[0], $participantsCount);
                $roundMatches[] = array($home, $away);
                $home = changeIntoBye($sum - $match[1], $participantsCount);
                $away = changeIntoBye($match[1], $participantsCount);
                $roundMatches[] = array($home, $away);
            }
            $matches = $roundMatches;
        }
    
        return $matches;
    
    }
    
    function changeIntoBye($seed, $participantsCount)
    {
        //return $seed <= $participantsCount ?  $seed : sprintf('%d (= bye)', $seed);  
        return $seed <= $participantsCount ?  $seed : null;
    }
    
    ?>
    
    Number of participants: 16
    Number of rounds: 4
    Bracket size: 16
    Required number of byes: 0
    C:\projects\draw\draw.php:7:
    array (size=8)
      0 => 
        array (size=2)
          0 => int 1
          1 => int 16
      1 => 
        array (size=2)
          0 => int 9
          1 => int 8
      2 => 
        array (size=2)
          0 => int 5
          1 => int 12
      3 => 
        array (size=2)
          0 => int 13
          1 => int 4
      4 => 
        array (size=2)
          0 => int 3
          1 => int 14
      5 => 
        array (size=2)
          0 => int 11
          1 => int 6
      6 => 
        array (size=2)
          0 => int 7
          1 => int 10
      7 => 
        array (size=2)
          0 => int 15
          1 => int 2
    
    Number of participants: 6
    Number of rounds: 3
    Bracket size: 8
    Required number of byes: 2
    C:\projects\draw\draw.php:7:
    array (size=4)
      0 => 
        array (size=2)
          0 => int 1
          1 => null
      1 => 
        array (size=2)
          0 => int 5
          1 => int 4
      2 => 
        array (size=2)
          0 => int 3
          1 => int 6
      3 => 
        array (size=2)
          0 => null
          1 => int 2
    
    int * pctournamentSeedArray(int PlayerCnt)
    {
        int * Array;
        int * PrevArray;
        int i;
    
        Array = meAlloc(sizeof(int) * PlayerCnt);
    
        if (PlayerCnt == 2)
        {
            Array[0] = 0;
            Array[1] = 1;
            return Array;
        }
    
        PrevArray = pctournamentSeedArray(PlayerCnt / 2);
        for (i = 0; i < PlayerCnt;i += 2)
        {
            Array[i] = PrevArray[i / 2];
            Array[i + 1] = (PlayerCnt - 1) - Array[i] ;
        }
        meFree(PrevArray);
        return Array;
    }