单循环赛 贝格尔编排法实现
原文鏈接
單循環賽,是指所有參賽隊伍都需跟其他隊伍比賽一次,根據比賽得分,勝負場次來排列名次。比賽隊伍為單數時,輪數等于隊伍數,為雙數時,輪數等于隊伍數減一。如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
3 - 6
4 - 5
第二輪將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。
運行效果
代碼實現
#include <iostream> using namespace std; void BegerArrangement(int nAmount) {if (nAmount < 2 || nAmount > 90)return;// 隊伍數量int nFixAmount = nAmount;// 最后一支隊伍的編號int nLastPlayerNo = nAmount;// 奇數隊伍,補上一支虛擬的隊伍,最后一支隊伍的編號為0if (nAmount % 2){++nFixAmount;nLastPlayerNo = 0;}// 輪數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){// 每次最后一個玩家的位置需要左右對調nLastPlayerPos = nFixAmount + 1 - nLastPlayerPos;if (nRound == 1)nFirstPlayerPos = 1;elsenFirstPlayerPos = (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];elsenPlayer[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);elseprintf("%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"); } int main() {int n;cin >> n;BegerArrangement(n);return 0; }代碼思路,編輯格式不易,大家覺得還可以可以點贊、收藏、關注一下吧!
也可以到我的個人博客參觀一下,https://motongxue.gitee.io
總結
以上是生活随笔為你收集整理的单循环赛 贝格尔编排法实现的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: wap网站制作教程,Github标星5.
- 下一篇: 大数据书单