分治法:
列出人數為的情況:
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);
}
- 遞迴時 (fun(n/2)函式)
當n/2為偶數的時候,繼續遞迴
當n/2為奇數的時候要進行修正。
- 返回求值時:(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
排列完畢。