1. 程式人生 > >網球迴圈賽思路 - 分治法求解(無程式碼)

網球迴圈賽思路 - 分治法求解(無程式碼)

分治法:

列出人數為的情況:

K = 1

1

2

2

1

其中第一列是選手的序號,之後n列代表著選手的對手

 

K = 2

1

2

3

4

2

1

4

3

3

4

1

2

4

3

2

1

 

可以看出,k=4的情況就是將格子分成四個部分,然後將人數為  的結果放在左上角和右下角的格子,然後再將人數結果加上再放在左下角和右上角的格子中去。

 

因此可以得出以下分治演算法:

 

void fun()

{

       if(n==1)

       {

              tables[0][0] = 1;

              return;

}

       fun(n/2);

       get_table(n);

}

 

  1. 遞迴時 (fun(n/2)函式)

當n/2為偶數的時候,繼續遞迴

當n/2為奇數的時候要進行修正。

 

  1. 返回求值時:(get_table()函式)

如果n為奇數,則計算n+1的情況,將最後一個選手當做虛擬選手。

虛擬選手的處理方法:將與虛擬選手比賽的選手視為輪空

如果n為偶數:

當n/2為偶數時,直接複製即可。

當n/2為奇數時,要進行修正。

修正方法為:

將n/2情況中的虛擬選手序號(虛擬選手序號大於當前的所有選手)全部變成當前選手序號加上n/2,然後將對應的虛擬選手賽程變成當前選手。不是虛擬選手的處理和情況相同(然後可以得到左上角和左下角的所有情況)。之後將除第一列以外剩餘n/2列複製到右半邊,之後再講對應選手按序號排序即可。

 

如:n=6時,n/2=3:

 

1  2  3  4

2  1  4  3

3  4  1  2

 

在上述情況中4是虛擬選手,因為其序號大於3

 

將虛擬選手的序號變成當前選手序號加上n/2

 

1      2  3  4

2      1  5  3

3      6  1  2

 

然後將虛擬選手的對手匹配

 

1      2  3  4

2      1  5  3

3      6  1  2

4            1

5         2

6      3

 

再正常填入:

1      2  3  4

2      1  5  3

3      6  1  2

4      5  6  1

5      4  2  6

6      3  4  5

 

最後將除第一列以外的所有元素左下角複製到右上角,左上角複製到右下角

 

2  3  4  5  6  1

1  5  3  4  2  6

6  1  2  3  4  5

5  6  1  2  3  4

4  2  6  1  5  3

3  4  5  6  1  2

 

最後再按序號順序從上到下排列整齊:

 

1  5  3  4  2  6

2  3  4  5  6  1

3  4  5  6  1  2

4  2  6  1  5  3

5  6  1  2  3  4

6  1  2  3  4  5

 

排列完