循环赛算法分析
這是一個(gè)算法作業(yè),老師說要用分治思想解決,在網(wǎng)上找了都講解的不是很明白,比賽對(duì)數(shù)為奇數(shù)時(shí),有點(diǎn)費(fèi)解。不過最后還是想明白了,順便把作業(yè)放這,有興趣了解的可以看一下,逃)
問題:
有N個(gè)運(yùn)動(dòng)員進(jìn)行單循環(huán)賽,即每個(gè)運(yùn)動(dòng)員要和所有其他運(yùn)動(dòng)員進(jìn)行一次比賽。
1.試用分治法為N個(gè)運(yùn)動(dòng)員安排比賽日程。
2.要求每個(gè)(或隊(duì))運(yùn)動(dòng)員每天只能進(jìn)行一場比賽,且當(dāng)運(yùn)動(dòng)員人數(shù)(隊(duì)數(shù))為偶數(shù)時(shí),整個(gè)比賽在N-1天內(nèi)結(jié)束,為奇數(shù)時(shí),在N天內(nèi)結(jié)束;
3.將運(yùn)動(dòng)員從1到N編號(hào)。
思路:
我們用表格的方式來表示循環(huán)賽的日程安排,最左邊的一列表示隊(duì)號(hào),每一行表示相應(yīng)隊(duì)比賽每天的對(duì)手,即a[i][j]表示第i隊(duì)第j天的對(duì)手。
我們從兩個(gè)隊(duì)的比賽開始,并發(fā)現(xiàn)其中規(guī)律:
其中,四隊(duì)的表格可以從兩隊(duì)的表格產(chǎn)生的:
但這只能解決2的冪的隊(duì)數(shù)的循環(huán)賽日程。
為了解決更普遍的隊(duì)數(shù),我們考慮隊(duì)數(shù)為偶數(shù)時(shí),它必然可以被2整除,商為偶數(shù)或奇數(shù)。商為偶數(shù)可以用上面的方法得到結(jié)果,商為奇數(shù)時(shí),就不行了。
我們先來看一個(gè)例子,隊(duì)數(shù)為6時(shí),它的一半為3,是奇數(shù),不能用上面的方法,我們先考慮它的子問題:隊(duì)數(shù)為4時(shí),就是上面求出的結(jié)果了,我們要從隊(duì)數(shù)4產(chǎn)生6的結(jié)果:
我們可以看到后3行其實(shí)和前3行是一樣的,只是編號(hào)變了而已。為了讓編號(hào)在6以內(nèi),我們要改變編號(hào)7的對(duì)應(yīng)情況,可以看出編號(hào)7是由編號(hào)4產(chǎn)生的,所以我們只要讓它們相對(duì)的隊(duì)組成一隊(duì)就可以了,即3-6,2-5,1-4。
至此,我們只解決了6隊(duì)的一部分情況,第5、6列還沒有產(chǎn)生:
由上面可知,第1行還缺5,6,第2行缺4,6,第3行缺4,5,那么它們?cè)撛趺磁帕胁挪粫?huì)沖突呢?我們看到1,2,3行的5,6列在4,5,6中取兩個(gè)值,可以用循環(huán)隊(duì)列的形式解決,如下:
到此,我們來想更普遍的情況,任意一個(gè)隊(duì)數(shù)n,是否都可以分解為上面的兩種情況?
首先,我們看任意n是否能終止分解?如下偽代碼:
對(duì)于任何大于2的數(shù)除以2再加1或者加1再除以2,它的規(guī)模都會(huì)縮小,所以這最終是可以終止的。接著我們看是否能分解為上面兩種情況:
n為奇數(shù)時(shí),用n+1代替計(jì)算,即轉(zhuǎn)化為偶數(shù)的隊(duì)數(shù)。
n為偶數(shù)時(shí),分兩種情況,(1)n/2為偶數(shù),(2)n/2為奇數(shù)。(1)繼續(xù)被2除,直到商為1,即轉(zhuǎn)化為第一種情況,n是2的冪,或者商為大于1的奇數(shù)(2),轉(zhuǎn)化為(2)。(2)就是第二種情況。所以,任意n是可以分解為上面兩種情況的,而且是可以終止的。
把上述的內(nèi)容一般化,即為我們解決該問題的解:
1.tournament(a[][],n)用遞歸把問題分解為多個(gè)子問題,其中odd(n)判斷n是否為奇數(shù),makecopy(a[][], n)用上面的兩種情況中的一種產(chǎn)生日程:
2.odd(n)判斷n是否為奇數(shù):
odd(n) return n&1;3.makecopy(a[][], n)用上面的兩種情況中的一種產(chǎn)生日程,如果n/2為偶數(shù)用第一種,即copy(a[][], n),n/2為奇數(shù)用第二種,即copyodd(a[][], n):
makecopy(a[][], n) m = n/2; if odd(m)copyodd(a[][], n); else copy(a[][], n);4.copy(a[][], n)第一種情況的日程產(chǎn)生方法,為了更好的理解,我們從1*1到2*2到4*4的表格產(chǎn)生情況開始(假設(shè)表為二維數(shù)組a):
1*1表產(chǎn)生2*2表是將a[0][0]加1放到a[0][1],再將這個(gè)值復(fù)制到a[1][0],將a[0][0]中的數(shù)復(fù)制到a[1][1].
同理,2*2表產(chǎn)生4*4表是將2*2表相應(yīng)位置(即4*4表左上角)加2放到右上角,再復(fù)制到左下角,將左上角復(fù)制到右下角:
5.copyodd(a[][], n)為第二種情況的日程產(chǎn)生方法,上面我們已經(jīng)了解了隊(duì)數(shù)為6時(shí)的產(chǎn)生情況,我們把情況一般化,隊(duì)數(shù)為n,且m=n/2為奇數(shù),且隊(duì)數(shù)為m+1的子情況已經(jīng)解決:
因?yàn)?m+1已經(jīng)超出n的范圍,所以我們將值為m+1和2m+1的隊(duì)組成一組,即1—m+1,2—m+2,3—m+3,……,m—n.
因?yàn)樗鼈冎g都相差m,所以可以用一個(gè)數(shù)組b的索引和值的對(duì)應(yīng)關(guān)系來表示:
至此,我們完成了部分對(duì)應(yīng)關(guān)系,接著要解決m+2到n列的對(duì)應(yīng)關(guān)系:
第1行還缺m+2……n;
第2行缺 m+3……n, m+1;
第3行缺 m+4……n, m+1,m+2;
……
第m行缺 m+1……n-1.
可以看出它們是在m+1到n之間循環(huán)取值,且每次取m-1個(gè)。所以,可以用一個(gè)包括2個(gè)m+1到n連續(xù)排列的數(shù)組表示:
0 1 …… m-1 m m+1 …… n-1
m+1 m+2 …… n m+1 m+2 …… n
剩下未分配的隨之解決。
循環(huán)賽算法到此完成。
數(shù)據(jù)結(jié)構(gòu):
一個(gè)二維數(shù)組a[n][n]存儲(chǔ)日程表,一個(gè)一維數(shù)組b[n]存儲(chǔ)映射關(guān)系。
效率分析:
T(n) = T(n/2)+f(n)
其中,f(n)為copy()的時(shí)間
f(n) = (n/2)^2
推出:T(n) = T(n/2)+(n/2)^2
因?yàn)槎挚梢苑謑og n次,所以T(n) = (n/2)^2+(n/4)^2+…+1 ;
所以,T(n)∈O(n^2)。
參考資料:
http://www.cppblog.com/cdy20/archive/2009/04/01/78573.html?yyue=a21bo.50862.201879#_Toc225487252
http://www.cnblogs.com/hoojjack/p/4211941.html
http://www.cnblogs.com/kelin1314/archive/2009/07/15/1523905.html
總結(jié)
- 上一篇: 介绍几款WAP网页制作工具(提供下载)
- 下一篇: 读书笔记《底层逻辑2·理解商业世界的本质