這是一張連連看的地圖,假設(shè)標(biāo)8和9的部分是兩張相同的牌。
在數(shù)組矩陣中,0表示沒有牌,大于1表示有牌。至于是什么牌,那是隨機(jī)的了。
不要告訴我,你說的“布局算法”是指怎么把牌剛剛好放上去,那個(gè)無所謂什么
算法,你只要首先在地圖數(shù)組中準(zhǔn)備好偶數(shù)個(gè)1,在布牌時(shí)保證每種牌是偶數(shù)個(gè)
(不同種類的牌用大于1的數(shù)來表示),相應(yīng)地放入每個(gè)1的位置上就可以了。
一、計(jì)算地圖上這兩張牌能不能連通(當(dāng)然能了,哈哈)。
這是連連看尋路算法的第一步。
先定義一下兩張牌能連的充分條件:
1.兩張牌是同一種。
2.兩張牌之間有一條全是0的路可以連通。
3.這一條路不能有兩個(gè)以上的拐角(corner)
滿足這三個(gè)條件,就可以認(rèn)為這兩張牌是可以連的。
首先,我們依據(jù)前兩個(gè)條件來完成一個(gè)基本的尋路算法。
我們的目的是從8到9找出一條可以連通的路來。
那么很明顯從8到9的第一步一其有四個(gè)方向可以選擇,分別是東,南,西,北
(e, s, w, n以中國地圖方向?yàn)闃?biāo)準(zhǔn))四個(gè)方向,在第一步中我們首先假設(shè)四
個(gè)方面沒有任何優(yōu)劣,那么我可以任意選擇一個(gè)方向移動(dòng),那就是東面吧。
圖二:
0, 0, 0, 0, 0, 0, 0, 0 , 0, 0
0, 8, -8, 0, 0, 0, 0, 0 , 0, 0
0, 0, 0, 0, 0, 0, 0, 0 , 0, 0
0, 0, 0, 0, 0, 0, 0, 0 , 0, 0
0, 0, 0, 0, 0, 0, 0, 0 , 0, 0
0, 0, 0, 0, 0, 0, 0, 0 , 0, 0
0, 0, 0, 0, 0, 0, 0, 0 , 0, 0
0, 0, 0, 0, 0, 0, 0, 0 , 9, 0
0, 0, 0, 0, 0, 0, 0, 0 , 0, 0
我從8向東移動(dòng)了一步,所以到達(dá)了-8的位置,我之所以可以移到-8位置,很明顯,
是因?yàn)?8的位置上原來是一個(gè)0,表示沒有牌阻擋。
那么現(xiàn)在尋路的問題就變成了,如何從-8找連通9的路了!
說到這里應(yīng)該明白了吧,好多費(fèi)話,有點(diǎn)像娘們在說話。
所以目前的尋路算法歸結(jié)為一個(gè)遞歸算法的基本問題。
先從8到找到下一個(gè)結(jié)點(diǎn)-8,再用同樣的規(guī)則,從-8找到下一個(gè)結(jié)點(diǎn),比如-88。。。
圖三:
0, 0, 0, 0, 0, 0, 0, 0 , 0, 0
0, 8, -8, -88, 0, 0, 0, 0 , 0, 0
0, 0, 0, 0, 0, 0, 0, 0 , 0, 0
0, 0, 0, 0, 0, 0, 0, 0 , 0, 0
0, 0, 0, 0, 0, 0, 0, 0 , 0, 0
0, 0, 0, 0, 0, 0, 0, 0 , 0, 0
0, 0, 0, 0, 0, 0, 0, 0 , 0, 0
0, 0, 0, 0, 0, 0, 0, 0 , 9, 0
0, 0, 0, 0, 0, 0, 0, 0 , 0, 0
如果一直都能OK,沒有阻礙的話,最后找到了9,就算成功以,如要有一步不能走下去了,
就再退回上個(gè)結(jié)點(diǎn),向別的方向發(fā)展,都不行,就再退回上級結(jié)點(diǎn),再向別的方向發(fā)展,
這里的邏輯就是遞歸的思想了。
用這樣的方法寫出來的算法已經(jīng)能在最優(yōu)的情形下用了,比如從8,到-88,哈哈。
但在稍微復(fù)雜的情況下,會(huì)產(chǎn)生奇多的遞歸結(jié)點(diǎn)。P4機(jī)也跑不動(dòng)啊。我試過,哈哈。
那么第二步就是為(e,s,w,n)四個(gè)方向加權(quán),也就是讓它們之間有一個(gè)優(yōu)先權(quán),說白了就
是先試哪一條路。決定的法則應(yīng)該有好幾個(gè)吧,比如以9號的位置來看,它處于8號的東南面,
那試路時(shí)當(dāng)然應(yīng)當(dāng)優(yōu)先選擇東面和南面,再比如9號如果牌8號的正東面,那當(dāng)然是選擇正東了。
再比如,當(dāng)走到-8的位置時(shí),明顯只能再走三個(gè)方向,因?yàn)樗遣荒芑仡^的。
經(jīng)過這樣的處理,遞歸算法生成的結(jié)點(diǎn)數(shù)會(huì)明顯變少,會(huì)更快的找到成功的路。但性能在最壞情況
下沒有本質(zhì)改變。
接下來,第三步,我們把第三個(gè)充分條件加進(jìn)來,來解決根本問題。
3.這一條路不能有兩個(gè)以上的拐角(corner)
按照面向?qū)ο蟮乃枷耄茏匀坏模医o每個(gè)在遞歸算法中生成的位置結(jié)點(diǎn)加上了個(gè)corner的屬性,
來記錄這條路到目前為止拐了幾個(gè)角。
這樣一下子就好辦了啊。如果發(fā)現(xiàn)這個(gè)結(jié)點(diǎn)已經(jīng)拐了兩個(gè)彎時(shí),如果要再拐彎,或者到達(dá)9之前注定
要再增加cornor時(shí),就果斷over,返回上級結(jié)點(diǎn)。
注意,要把二、三兩步的條件綜合起來詳細(xì)規(guī)劃一個(gè)個(gè)可能性,盡可能提早讓不可能的結(jié)點(diǎn)OVER,
這就是提高性能的關(guān)鍵吧。算法預(yù)見性越強(qiáng),性能就越高吧。
我們的算法在賽揚(yáng)500,256M的機(jī)器上,10萬次平均結(jié)果是一次運(yùn)算花時(shí)不超過0.1毫秒,算得還不
精確,速度確實(shí)很快,因?yàn)樵诤軌牡那樾蜗拢a(chǎn)生的最大結(jié)點(diǎn)數(shù)是690幾個(gè),這樣必然會(huì)很快的
,詳細(xì)的數(shù)據(jù)已經(jīng)記不清了。
說了這么多了,應(yīng)當(dāng)明白第一步連通算法的思路了吧,我所知道的,都已經(jīng)盡可能的講出來了。
這個(gè)算法完全是自己按照連連看的特點(diǎn),度身定做的。因?yàn)槭且徊讲絫est出來的,所以我個(gè)人
覺得是很自然的,沒有任何高深的地方,完成后,性能也很好,這才覺得是如此的簡單。相信大家
仔細(xì)看看就能寫出自己的算法來的吧。
二、整個(gè)地圖有沒有解???可以連通的總牌數(shù)?
這是一個(gè)問題。
解決這個(gè)問題之前,我們先來解決提示功能(hint)就是為玩家提供提示,哪一對牌可以連
通。
我的做法是,先把整個(gè)地圖中相同牌歸到一起,用數(shù)組也好,鏈表也好。
像這樣,
4,4,4,4
5,5,5,5
6,6,6,6
......
然后計(jì)算比如4個(gè)4之間有哪兩對可以連,至于如何判斷能不能連,第一步算法已經(jīng)實(shí)現(xiàn)了吧,哈哈。
一發(fā)現(xiàn)有可以連的牌就退出來,告訴玩家這兩張牌可以連啊!
這就OK了。
這完全是建立在第一步算法的基礎(chǔ)上實(shí)現(xiàn)的。
好的,hint功能可以了,
那么,整個(gè)地圖沒有解的算法是不是出來了?
是的,如果找不到可以hint的牌,那當(dāng)然就是沒有解了!
把所有可以hint的對數(shù)記下來,就是總的可以連通數(shù)了。
至此,與連連看所有算法有關(guān)的問題解決完畢。
第二步算法的實(shí)現(xiàn),明顯開銷要大很多,最壞情況應(yīng)當(dāng)會(huì)是單次連通算法計(jì)算量的大約50倍以上
(與牌的總數(shù)量和擺的位置有關(guān))還好在一般的服務(wù)器上單次連通計(jì)算花的時(shí)間實(shí)在太少了,
實(shí)際運(yùn)行中完全可以很流暢。以上數(shù)據(jù)都是我估計(jì)的理論值,因?yàn)閷?shí)際測試時(shí)一直沒有問題,
我也懶得計(jì)算出真正比較可靠的均值了。
這一部分也是我認(rèn)為可以有所改進(jìn)的部分,公開出來,也希望大家能提供一些更好,更巧妙
的方法,我覺得我計(jì)算連通數(shù)和有無解的方法是比較笨的方法,幾乎是仗著基本的算法快,一
個(gè)一個(gè)算出來的。有沒有更好的方法呢?期待中...
只有注冊用戶登錄后才能發(fā)表評論。 | ||
![]() |
||
網(wǎng)站導(dǎo)航:
博客園
IT新聞
Chat2DB
C++博客
博問
管理
|
||
相關(guān)文章:
|
||