單循環(huán)賽,是指所有參賽隊伍都需跟其他隊伍比賽一次砂蔽,根據(jù)比賽得分洼怔,勝負場次來排列名次。比賽隊伍為單數(shù)時左驾,輪數(shù)等于隊伍數(shù)镣隶,為雙數(shù)時,輪數(shù)等于隊伍數(shù)減一诡右。如5支隊伍需比賽5輪安岂,6支隊伍需比賽5輪。
首先介紹下逆時針輪轉(zhuǎn)法帆吻。將隊伍用阿拉伯?dāng)?shù)字從1開始編號域那,編排時將參賽隊伍平均分成左右兩排,左邊從1開始自上向下排桅锄,右邊按號數(shù)自下向上排琉雳,形成一個U型結(jié)構(gòu)。如果隊伍數(shù)為奇數(shù)友瘤,則在最后加一個“0”翠肘,湊成偶數(shù)。與0比賽的隊伍該輪輪空辫秧。假設(shè)現(xiàn)在有7支隊伍參賽束倍,加上一個0,湊成8支盟戏。根據(jù)前面所述排列好隊伍绪妹,然后將左右兩排分別平行連線,就形成第一輪比賽的編排表柿究,即1-0邮旷,2-7,3-6蝇摸,4-5婶肩,隊伍1在該輪輪空办陷。第二輪開始,固定左上角的數(shù)字1律歼,其余的數(shù)字想象成一個環(huán)民镜,按逆時針方向移動一個位置,就形成第二輪的編排表险毁。以此類推制圈,每一輪移動一個位置,生成剩余輪次的編排表畔况。最終形成的編排表如下:
<pre>
一 二 三 四 五 六 七
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
</pre>
仔細觀察鲸鹦,會發(fā)現(xiàn)從第4輪開始,隊伍6總是跟上一輪輪空的隊伍比賽问窃,這就是逆時針輪轉(zhuǎn)法的缺點亥鬓,即第二輪的輪空隊從第四輪開始完沪,每輪都與前一輪的輪空隊伍比賽域庇。
貝格爾編排法與逆時針輪轉(zhuǎn)法類似,不過有兩個區(qū)別覆积。一是交替固定最大的數(shù)字(或者0)在左上角和右上角听皿,當(dāng)前輪次在左上角,則下一輪固定到右上角宽档。二是固定最大數(shù)字(或者0)后尉姨,剩余的數(shù)字想象成一個環(huán),移動一定間隔吗冤,這個間隔根據(jù)隊伍數(shù)決定:
<pre>
隊伍數(shù) 間隔數(shù)
<=4 0
5 - 6 1
7 - 8 2
9 -10 3
11-12 4
13-14 5
... ...
</pre>
假設(shè)有n(n>=4)支隊伍參賽又厉,則間隔數(shù)的計算公式為(n+n%2-4)/2。
同樣以7支隊伍參賽為例椎瘟,首輪還是
<pre>
1 - 0
2 - 7
3 - 6
4 - 5
</pre>
第二輪將0移到左上角覆致,剩下的數(shù)字從1開始逆時針移動2個間隔,這里1將移到原來4所在的位置
第三輪將0移動到右上角肺蔚,剩下的數(shù)字繼續(xù)逆時針移動2個間隔
剩下的輪次原理同上煌妈,最終編排表如下
代碼實現(xiàn)的思路如下,最大數(shù)字的位置只需根據(jù)前一輪的位置就能確定宣羊,其他數(shù)字都是按順序排列璧诵,形成一個有序的環(huán)。所以只需要確定1的位置仇冯,其他位置的數(shù)字都能確定之宿。將位置按照第一輪的數(shù)字編號為1-8。在第一輪苛坚,1在位置1上比被。第二輪坪创,1移動2個間隔,可以理解成移動3個位置姐赡,即1+3=4莱预,取模一下,(1+3)%7=4项滑,所以1將移到位置4依沮。第三輪,繼續(xù)移動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。
<pre>
void BegerArrangement(int nAmount)
{
if (nAmount < 2 || nAmount > 90 )
return;
// 隊伍數(shù)量
int nFixAmount = nAmount;
// 最后一支隊伍的編號
int nLastPlayerNo = nAmount;
// 奇數(shù)隊伍弧呐,補上一支虛擬的隊伍闸迷,最后一支隊伍的編號為0
if (IsOdd(nAmount))
{
++nFixAmount;
nLastPlayerNo = 0;
}
// 輪數(shù)
int nMaxRound = nFixAmount-1;
int nHalfAmount = nFixAmount / 2;
// 移動的間隔
int nStep = nFixAmount <= 4 ? 1 : (nFixAmount - 4) / 2 + 1;
int nRound = 1;
int nFirstPlayerPos = 1;
int nLastPlayerPos = 1;
int result[100][200] = { 0 };
while (nRound <= nMaxRound)
{
// 每次最后一個玩家的位置需要左右對調(diào)
nLastPlayerPos = nFixAmount + 1 - nLastPlayerPos;
if (nRound == 1)
nFirstPlayerPos = 1;
else
nFirstPlayerPos = (nFirstPlayerPos + nStep) % (nFixAmount - 1);
if (nFirstPlayerPos == 0)
nFirstPlayerPos = nFixAmount - 1;
if (nFirstPlayerPos == nLastPlayerPos)
nFirstPlayerPos = nFixAmount + 1 - nLastPlayerPos;
for (int i = 1; i <= nHalfAmount; ++i)
{
int nPos[2] = { i, nFixAmount - i + 1 };
int nPlayer[2] = { 0, 0 };
for (int j = 0; j < 2; ++j)
{
if (nPos[j] == nLastPlayerPos)
nPlayer[j] = nLastPlayerNo;
else if (nPos[j] < nFirstPlayerPos)
nPlayer[j] = nFixAmount - nFirstPlayerPos + nPos[j];
else
nPlayer[j] = nPos[j] - nFirstPlayerPos + 1;
result[i-1][(nRound-1)*2+j] = nPlayer[j];
}
}
++nRound;
}
for (int i = 1; i <= nMaxRound; ++i)
{
if( i == 1 )
printf("%3s%-3d|", "r", i);
else
printf("%4s%-3d|", "r", i);
}
printf("\n");
for (int i = 0; i < nHalfAmount; ++i)
{
for (int j = 0; j < nMaxRound; ++j)
{
printf("%-2d-%2d | ", result[i][j*2], result[i][j*2+1]);
}
printf("\n");
}
printf("\n\n");
}
</pre>
代碼地址:https://github.com/windpenguin/WindUtilities
參考
http://www.xxkt.cn/zhxk/2007/24920.html
http://baike.baidu.com/item/%E5%8D%95%E5%BE%AA%E7%8E%AF%E8%B5%9B%E5%88%B6?sefr=enterbtn
http://baike.baidu.com/item/%E8%B4%9D%E6%A0%BC%E5%B0%94%E7%BC%96%E6%8E%92%E6%B3%95?sefr=enterbtn