问题描写叙述:

    设有n(n=2^k)支队伍參加循环赛,循环赛共进行n-1天,每支队伍要与其它n-1支队伍比赛一场,且每支队伍每天必须比赛一场,不能轮空。试按此要求为比赛安排日程。

 

算法思路:

   我们先安排奇数下标位置与偶数下标位置之间的比赛,就有n/2场,方法非常easy,team[2k]=2k,全部奇数号组成一个序列[1,3...n-1],然后循环移动n/2-1次(比方第2个序列就是[3,5...n-1,1]),然后将该序列填充在team的奇数位置上。

   接下来将队伍一分为二,奇数为一组,偶数为一组,分配安排其内部比赛(由于奇偶数之间前面已经安排过了啦)。以奇数组[1,3,5,7]为例(以n=8为例说明),我们仍然先安排奇数下标位置与偶数下标位置之间的比赛,也就是[15]与[37]之间的比赛,共同拥有2场(n/4)。

   接下来,再将队伍一分为二,得到[15],[37],[04],[26],对每一部分,仍然是先安排奇数下标位置与偶数下标位置之间的比赛,共1场(n/8)。此时已不可再分出子队伍,计算结束。

    

对照赛安排编号:

    从前文的分析能够看出,我们产生比赛日程安排是有规律可循,先产生n/2,然后是n/4,...直到最后1场。因为n=2^k,那么这些安排场次总数为2^(k-1)+2^(k-2)...+1=2^k-1=n-1,恰好相符(其实是必定的)。

    这样,对于给定一个编号id,我们首先能够判定相应场次安排须要进行几次队伍分裂。方法非常easy,比如n=8,id=6,因为一次分烈得到n/2=4场,再次分裂可得n/4=2场,于是两次分裂就可以。同一时候id-4=2,也就是说两次分裂后的第2个赛场安排,这个2用于对子队伍移位计算使用。

 

參考代码:

 


 



  1. // team: 比赛安排结构,team[2k] vs team[2k+1] 
  2. // len:  team的总数 
  3. // id:   第id轮的安排,id的范围[1, len-1] 
  4. void game(int *team, int len, int id){
  5.     int base = 2;
  6.     while (id > len/base){
  7.         id -= len/base;
  8.         base <<= 1;
  9.     }
  10.     for (int i=0; i<base/2; ++i){
  11.         int start = i+base/2+(id-1)*base;
  12.         for (int j=0; j<len/base; ++j){
  13.             team[i*2*len/base+2*j] = base*j+i;
  14.             team[i*2*len/base+2*j+1] = (start+base*j)%len;
  15.         }
  16.     }
  17. }
  18. ////////////////////////////////////////////////////////////////////////
  19. // 以下是測试部分
  20. void dump(int *arr, int len){
  21.     for (int i=0; i<len; i+=2)
  22.         printf("%02d-%02d ", arr[i], arr[i+1]);
  23.     printf("/n");
  24. }
  25. int main(){
  26.     const int len = 16;
  27.     int team[len];
  28.     for (int i=1; i<len; ++i){
  29.         game(team, len, i);
  30.         printf("[%02d] ", i);
  31.         dump(team, len);
  32.     }
  33.     return 0;
  34. }


输出结果:

[01] 00-01 02-03 04-05 06-07 08-09 10-11 12-13 14-15

[02] 00-03 02-05 04-07 06-09 08-11 10-13 12-15 14-01

[03] 00-05 02-07 04-09 06-11 08-13 10-15 12-01 14-03

[04] 00-07 02-09 04-11 06-13 08-15 10-01 12-03 14-05

[05] 00-09 02-11 04-13 06-15 08-01 10-03 12-05 14-07

[06] 00-11 02-13 04-15 06-01 08-03 10-05 12-07 14-09

[07] 00-13 02-15 04-01 06-03 08-05 10-07 12-09 14-11

[08] 00-15 02-01 04-03 06-05 08-07 10-09 12-11 14-13

[09] 00-02 04-06 08-10 12-14 01-03 05-07 09-11 13-15

[10] 00-06 04-10 08-14 12-02 01-07 05-11 09-15 13-03

[11] 00-10 04-14 08-02 12-06 01-11 05-15 09-03 13-07

[12] 00-14 04-02 08-06 12-10 01-15 05-03 09-07 13-11

[13] 00-04 08-12 01-05 09-13 02-06 10-14 03-07 11-15

[14] 00-12 08-04 01-13 09-05 02-14 10-06 03-15 11-07

[15] 00-08 01-09 02-10 03-11 04-12 05-13 06-14 07-15