单循环赛,是指所有参赛队伍都需跟其他队伍比赛一次,根据比赛得分,胜负场次来排列名次。比赛队伍为单数时,轮数等于队伍数,为双数时,轮数等于队伍数减一。如 5 支队伍需比赛 5 轮,6 支队伍需比赛 5 轮。
首先介绍下逆时针轮转法。将队伍用阿拉伯数字从 1 开始编号,编排时将参赛队伍平均分成左右两排,左边从 1 开始自上向下排,右边按号数自下向上排,形成一个 U 型结构。如果队伍数为奇数,则在最后加一个 "0",凑成偶数。与 0 比赛的队伍该轮轮空。假设现在有 7 支队伍参赛,加上一个 0,凑成 8 支。根据前面所述排列好队伍,然后将左右两排分别平行连线,就形成第一轮比赛的编排表,即 1-0,2-7,3-6,4-5,队伍 1 在该轮轮空。第二轮开始,固定左上角的数字 1,其余的数字想象成一个环,按逆时针方向移动一个位置,就形成第二轮的编排表。以此类推,每一轮移动一个位置,生成剩余轮次的编排表。最终形成的编排表如下:
一 二 三 四 五 六 七
1—0 1—7 1—6 1—5 1—4 1—3 1—2
2—7 0—6 7—5 6—4 5—3 4—2 3—0
3—6 2—5 0—4 7—3 6—2 5—0 4—7
4—5 3—4 2—3 0—2 7—0 6—7 5—6
仔细观察,会发现从第 4 轮开始,队伍 6 总是跟上一轮轮空的队伍比赛,这就是逆时针轮转法的缺点,即第二轮的轮空队从第四轮开始,每轮都与前一轮的轮空队伍比赛。
贝格尔编排法与逆时针轮转法类似,不过有两个区别。一是交替固定最大的数字(或者 0)在左上角和右上角,当前轮次在左上角,则下一轮固定到右上角。二是固定最大数字(或者 0)后,剩余的数字想象成一个环,移动一定间隔,这个间隔根据队伍数决定:
队伍数 间隔数
<=4 0
5 - 6 1
7 - 8 2
9 -10 3
11-12 4
13-14 5
... ...
假设有 n(n>=4)支队伍参赛,则间隔数的计算公式为 (n+n%2-4)/2。
同样以 7 支队伍参赛为例,首轮还是
1 - 0
2 - 7
第二轮将 0 移到左上角,剩下的数字从 1 开始逆时针移动 2 个间隔,这里 1 将移到原来 4 所在的位置
第三轮将 0 移动到右上角,剩下的数字继续逆时针移动 2 个间隔
剩下的轮次原理同上,最终编排表如下
代码实现的思路如下,最大数字的位置只需根据前一轮的位置就能确定,其他数字都是按顺序排列,形成一个有序的环。所以只需要确定 1 的位置,其他位置的数字都能确定。将位置按照第一轮的数字编号为 1-8。在第一轮,1 在位置 1 上。第二轮,1 移动 2 个间隔,可以理解成移动 3 个位置,即 1+3=4,取模一下,(1+3)%7=4,所以 1 将移到位置 4。第三轮,继续移动 3 个位置,(4+3)%7=0,这里 0 就是 7,也就是 1 移到位置 7。第四轮,(7+3)%7=3,1 移到位置 3。以此类推。要注意的是,要是 1 移到的位置跟 0 冲突,就移到相对位置。0 在位置 8,那么 1 就移到位置 1,0 在位置 1,1 就移到位置 8。
- 1 void BegerArrangement(int nAmount) 2 {
- 3
- if (nAmount < 2 || nAmount > 90) 4
- return;
- 5 6 // 队伍数量
- 7 int nFixAmount = nAmount;
- 8 // 最后一支队伍的编号
- 9 int nLastPlayerNo = nAmount;
- 10 // 奇数队伍,补上一支虚拟的队伍,最后一支队伍的编号为0
- 11
- if (IsOdd(nAmount)) 12 {
- 13++nFixAmount;
- 14 nLastPlayerNo = 0;
- 15
- }
- 16 // 轮数
- 17 int nMaxRound = nFixAmount - 1;
- 18 int nHalfAmount = nFixAmount / 2;
- 19 20 // 移动的间隔
- 21 int nStep = nFixAmount <= 4 ? 1 : (nFixAmount - 4) / 2 + 1;
- 22 23 int nRound = 1;
- 24 int nFirstPlayerPos = 1;
- 25 int nLastPlayerPos = 1;
- 26 int result[100][200] = {
- 0
- };
- 27
- while (nRound <= nMaxRound) 28 {
- 29 // 每次最后一个玩家的位置需要左右对调
- 30 nLastPlayerPos = nFixAmount + 1 - nLastPlayerPos;
- 31 32
- if (nRound == 1) 33 nFirstPlayerPos = 1;
- 34
- else 35 nFirstPlayerPos = (nFirstPlayerPos + nStep) % (nFixAmount - 1);
- 36 37
- if (nFirstPlayerPos == 0) 38 nFirstPlayerPos = nFixAmount - 1;
- 39 40
- if (nFirstPlayerPos == nLastPlayerPos) 41 nFirstPlayerPos = nFixAmount + 1 - nLastPlayerPos;
- 42 43
- for (int i = 1; i <= nHalfAmount; ++i) 44 {
- 45 int nPos[2] = {
- i,
- nFixAmount - i + 1
- };
- 46 int nPlayer[2] = {
- 0,
- 0
- };
- 47
- for (int j = 0; j < 2; ++j) 48 {
- 49
- if (nPos[j] == nLastPlayerPos) 50 nPlayer[j] = nLastPlayerNo;
- 51
- else if (nPos[j] < nFirstPlayerPos) 52 nPlayer[j] = nFixAmount - nFirstPlayerPos + nPos[j];
- 53
- else 54 nPlayer[j] = nPos[j] - nFirstPlayerPos + 1;
- 55 56 result[i - 1][(nRound - 1) * 2 + j] = nPlayer[j];
- 57
- }
- 58
- }
- 59 60++nRound;
- 61
- }
- 62 63
- for (int i = 1; i <= nMaxRound; ++i) 64 {
- 65
- if (i == 1) 66 printf("%3s%-3d|", "r", i);
- 67
- else 68 printf("%4s%-3d|", "r", i);
- 69
- }
- 70 printf("\n");
- 71 72
- for (int i = 0; i < nHalfAmount; ++i) 73 {
- 74
- for (int j = 0; j < nMaxRound; ++j) 75 {
- 76 printf("%-2d-- | ", result[i][j * 2], result[i][j * 2 + 1]);
- 77
- }
- 78 printf("\n");
- 79
- }
- 80 81 printf("\n\n");
- 82
- }
代码地址
参考
来源: http://www.cnblogs.com/windpenguin/p/6501614.html