青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品

huaxiazhihuo

 

C++代碼(2)八皇后問題

        八皇后實在太有名了,我也就不廢話了。利用回溯算法,不難寫出其代碼,相信各位同學也都干過了。那這篇文章還有何新意呢?難道是向各位展示在下的代碼要比各位好,絕對不是。只因用C++寫代碼的時候,很容易就陷入各種細節的糾纏中,必須牢記大刀闊斧地砍除無關緊要的細節,始終堅持用C++清晰地表達解決問題的思路,嚴格遵守單一職責的規則,集中精力解決問題,不賣弄半點花巧。這是在下努力的一種嘗試。
        八皇后的解決方案,相信大家也都知道了,請恕我直奔主題了。
        由于長年累月沉浸于C++中,中毒已經甚深了,碰到任何問題,都條件反射地將其大御八塊,然后用CLASS來組織。于是,非常自然的,我決定用類QueenGame來表示八皇后這個游戲,用Play來擺弄出一個安全棋局。當然,不用CLASS,也依然可以寫出清晰的代碼,但是,感覺總是很不習慣。于是,main起來就非常簡單了。
int main()
{
    QueenGame game(
8);
    
if(game.Play())
        DisplayQueen(game);
    
return 0;
}

        為何不讓DisplayQueens成為QueenGame的成員,那是因為最后的結果不止顯示于控制臺,也可能要寫入文件中,也可能會繪制于窗口上,而且就算于控制臺上,也有多種輸出方式,種種可能,無窮無盡,QueenGame難道要用一大堆成員函數來應付這些顯示要求,這無疑不切合實際,而且也將污染QueenGame的接口。當一個類無法預料一件操作將如何發生的時候,就應該把這個決定交給上層調用來決定好了,這也是C++一貫的作法,既然我不知道怎么辦,那就由用戶來決定好了。我們要保持清醒,QueenGame的職責只是要擺出讓各個Queen和平共處的局面,至于其他的事情,那都不屬于自己的事情。不在其位,不謀其政。
        接下來就要思考QueenGame里面有那些東東,除了Play,肯定還有一些其他東東,最起碼也應該有些房子來供皇后們居住。最自然的想法是用一個二維的bool數組chessboard來表示棋盤,假如chessboard[i][j]為true,就表示皇后在上面。但是,目前市面上的作法是用數組來儲存N個皇后的位置,數組上的元素的索引表示皇后在棋盤上第幾行,其值對應皇后在第幾列上,這種儲存方式相當方便高效,二維數組如何搗鼓,都沒它方便。因此,可以這樣定義后宮的地點int m_QueenPos[N],代碼有點呆板,似乎應該用使用指針或者引入vector,來靈活處理不同數量的N個皇后,但這樣做,將引入一些其他的復雜性,對于本道程序,大可以假設皇后不會太多,10個已經足夠多了,犧牲一點點空間,來踢開這個細節,換取程序的安全穩定,我非常樂意。
        由于QueenGame可以Play不同數目的皇后,從1個到10個都可以,因此在QueenGame的構造函應該確立皇后的數量,同時,再提供一個函數GetQueenCount,用以獲取她們的數目。QueenGame的初版如下:
class QueenGame
{
public:
    
enum {MAX_QUEEN_COUNT = 10};
    QueenGame(
int queenCount);
public:
    
int GetQueenCount()const;
    
bool Play();
private:
    
int m_QueenPos[MAX_QUEEN_COUNT];
}
;
有了這些信息,就可以開始實作DisplayQueen了。但在此之前,還要解決一個問題,就是QueenGame如何讓外部函數來訪問它的棋盤局面呢?我的作法是直接暴露m_QueenPos,這不是公然違背了面向對象的封裝規定嗎?這樣做,我不會感到一絲絲的不安,因為除此之外,沒有更好的辦法了,其他的種種方案,都屬無病呻吟。比如說,仿效標準庫作法,typename一個迭代器,然后再搗鼓出一個begin和end的函數,這將要花費多少精力啊,這么做,僅僅是為了取悅封裝要求,而與原本要解決的問題根本是風馬牛不相及。那么采用GetQueenPos返回m_QueenPos的地址呢?這與直接訪問m_QueenPos并沒有多大的區別,如果以為這樣就可以滿足封裝,就可以享受封裝帶來的好處,純屬在自欺欺人罷了。還是一個辦法,就是讓DisplayQueens成為QueenGame的friend,這樣就可以不破壞封裝性,但如DisplayQueens不要為QueenGame的函數成員類似,既然DisplayQueens要為友元,那么WriteQueens也應為friend了,ShowQueens也應為friend了,為了滿足封裝,搞出這么多花招,畫蛇添足。……,但是,這樣直接暴露內部狀態,總是不安全的,那也沒什么,只要訂下規則,類外的一切函數不允許修改類的數據成員就OK了??傊也幌朐谌绾卧L問m_QueenPos這個小細節上耗費一丁點精力了,我的精力應該集中在原本要解決的問題上。
void DisplayQueen(const QueenGame& game)
{
    
using namespace std;
    
int count = game.GetQueenCount();
    
for (int n = 0; n<count; n++)
    
{
        
for (int i=1; i<=count; i++)
        
{
            
if (game.m_QueenPos[n] == i)
                cout 
<< "Q";
            
else
                cout 
<< "+";
        }

        cout 
<< endl;
    }

    cout 
<< endl;
}
        好了,做足準備工作了,終于來到問題核心了,實作QueenGame的Play函數。這可不是一件容易的事情,起碼不像前面的代碼那么容易好寫。來回顧一下我們聰明的大腦是如何處理這個問題的。面對著棋盤,我們手里拿著8個皇后,先把第1個皇后擺到第1行的第1列上開始,然后按照規則擺放第2個,也即是在第1個皇后的淫威之外給第2個皇后尋找第1個安身之所(總共有6個),然后再在第1、2個皇后的勢力范圍之外給第3個皇后謀求第1個住所,可知越往后,皇后們的生存空間將越來越狹窄,以至于在第N個皇后的時候,已無安身之所,說明第N-1個皇后的位置不恰當,將她挪到下一個地方,然后再嘗試擺上第N個皇后,如果嘗試遍了第N-1個皇后的住所,都無法給第N個皇后提供一個去處,說明第N-1個皇后的位置不當,回溯到第N-2個皇后上,然后擺上第N-1個皇后,用這個方法,最后終究能安頓好8個皇后。接下來,就是將其轉換成代碼,很明顯,這里出現了遞歸。代碼的關鍵在于,當擺上了第N個皇后時,如何表達第N+1個皇后的擺法,當無法擺上時,又該如何回溯到第N-1個皇后上去。當然,該如何停止遞歸,也不能不考慮。
bool QueenGame::Play()
{
    
int& lastPos = m_QueenPos[m_nLast];
    
while (++lastPos <= m_nQueenCount)
    
{
        
if (testNewQueen())
            
break;
    }

    
if (lastPos > m_nQueenCount)
    
{
        m_nLast
--;
        
if (m_nLast<=0 && m_QueenPos[0> m_nQueenCount)
            
return false;
    }

    
else
    
{
        
if (m_nLast+1 == m_nQueenCount)
            
return true;
        m_nLast
++;
        m_QueenPos[m_nLast] 
= 0;    
    }

    
return Play();
}

        代碼用m_nLast紀錄Play到第幾行了。其實這個變量可以省掉的,只要重新再寫一個Play的輔助函數PlayHelper,其帶有m_nLast的參數,內部遞歸調用自己。但是,在下寫代碼的原則是,能少寫函數就少寫函數,而且用了m_nLast之后,這個程序還有一個新的功能。于是,QueenGame的定義如下。
class QueenGame
{
public:
    
enum {MAX_QUEEN_COUNT = 10};

    QueenGame(
int queenCount)
    
{
        assert(queenCount 
> 0 && queenCount <= MAX_QUEEN_COUNT );
        m_nQueenCount 
= queenCount;
        m_nLast 
= 0;
        m_QueenPos[m_nLast] 
= 0;
    }


public:
    
int GetQueenCount()const
    
{
        
return m_nQueenCount;
    }

    
bool Play();

    
int m_QueenPos[MAX_QUEEN_COUNT];

private:
    
bool testNewQueen();

    
int m_nQueenCount;
    
int m_nLast;
}
;
        私有函數testNewQueen用以最后的位置是否適合第N個皇后居住,分別從縱向和斜向上予以考察,橫向就不用再考慮了,你應該知道WHY的。     
bool QueenGame::testNewQueen()
{
    
int lastPos = m_QueenPos[m_nLast];
    
for (int i=0; i<m_nLast; i++)
    
{
        
if (m_QueenPos[i] == lastPos || abs(m_QueenPos[i]-lastPos)==(m_nLast-i))
            
return false;
    }

    
return true;
}

        激動人心的一刻來臨了,程序終于可以跑起來了。再次審視代碼的時候,我們驚喜地發現QueenGame的Play函數可以遍歷所有的解,只要將main中的if改成while就可以了,非常棒。這都是堅持分離代碼的操作與輸出,并序將八皇后問題封裝成類所帶來的好處。
        顯然,這里采用了深度優先的搜索算法,代碼也可以寫成不用遞歸的形式,還有,這里也可以用寬度優先搜索法,這一切就有待各位嘗試了。
        又,程序采用了一點點匈牙利的命名習慣,這是MFC用久了所沾染上的惡習,沒辦法改了,偶也知道匈牙利命名的種種弊端。

posted on 2011-07-13 19:12 華夏之火 閱讀(3244) 評論(4)  編輯 收藏 引用

評論

# re: C++代碼(2)八皇后問題[未登錄] 2011-07-14 21:14 cexer

樓主你的文章質量都不錯,就是有點偏離群眾口味。  回復  更多評論   

# re: C++代碼(2)八皇后問題 2011-07-15 08:45 華夏之火

@cexer
謝謝,這是一個系列,打算用C++清晰地表達一些玩具程序,干點實事,而不是整天用C++玩弄一些華而不實的語言技巧
  回復  更多評論   

# re: C++代碼(2)八皇后問題 2011-07-15 09:15 Paw

我很喜歡這個系列,LZ的編程能力很NX。。。很喜歡看  回復  更多評論   

# re: C++代碼(2)八皇后問題 2011-07-15 10:34 黑莓掌

C++這種程序,從技術上來講,挺高級的.  回復  更多評論   


只有注冊用戶登錄后才能發表評論。
網站導航: 博客園   IT新聞   BlogJava   博問   Chat2DB   管理


導航

統計

常用鏈接

留言簿(6)

隨筆分類

隨筆檔案

搜索

積分與排名

最新評論

閱讀排行榜

評論排行榜

青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品
  • <ins id="pjuwb"></ins>
    <blockquote id="pjuwb"><pre id="pjuwb"></pre></blockquote>
    <noscript id="pjuwb"></noscript>
          <sup id="pjuwb"><pre id="pjuwb"></pre></sup>
            <dd id="pjuwb"></dd>
            <abbr id="pjuwb"></abbr>
            日韩午夜电影av| 欧美日韩高清在线| 蜜桃av一区二区在线观看| 亚洲婷婷免费| 亚洲精品国产视频| 在线免费观看日韩欧美| 国产午夜精品久久| 国产婷婷精品| 极品少妇一区二区三区| 国产一区91| 国内精品久久久久国产盗摄免费观看完整版| 国产精品成人免费精品自在线观看| 欧美日韩国产亚洲一区| 欧美日韩国产色综合一二三四 | 亚洲精品中文字幕在线观看| 亚洲黄网站黄| 久久影院亚洲| 欧美大色视频| 亚洲精品乱码久久久久久日本蜜臀 | 久久精品成人欧美大片古装| 久久野战av| 午夜精品理论片| 欧美一级专区| 蜜臀91精品一区二区三区| 欧美大秀在线观看 | 欧美日韩视频在线一区二区 | 亚洲性av在线| 久久成人18免费观看| 亚洲欧美日韩国产一区二区三区| 亚洲视频综合| 久久九九国产精品| 欧美高清视频在线播放| 亚洲美女av网站| 香蕉精品999视频一区二区| 久久久久九九九九| 欧美伦理a级免费电影| 国产精品日韩在线| 亚洲国产成人在线播放| 亚洲网站啪啪| 久久躁狠狠躁夜夜爽| 亚洲三级观看| 欧美一区二区视频网站| 欧美精品三级| 国产午夜精品一区二区三区视频 | 欧美大胆成人| 亚洲日本激情| 欧美一区网站| 欧美午夜一区二区福利视频| 韩国av一区二区| 国产精品久久久久久久浪潮网站| 欧美视频在线观看免费| 欧美成人日本| 国产亚洲免费的视频看| 亚洲免费观看视频| 久久久久成人精品| 99国内精品久久| 浪潮色综合久久天堂| 免费高清在线一区| 国产精品成人av性教育| 亚洲国产高清aⅴ视频| 亚洲在线播放| 亚洲经典在线看| 久久夜色精品亚洲噜噜国产mv| 久久色在线播放| 欧美久久久久久久久| **网站欧美大片在线观看| 久久一区二区三区超碰国产精品| 久久精品国产亚洲精品| 一区二区欧美日韩| 欧美国产视频日韩| 亚洲图片在线| 激情欧美一区二区三区| 亚洲日韩欧美一区二区在线| 欧美香蕉大胸在线视频观看| 亚洲第一精品在线| 国产精品海角社区在线观看| 亚洲三级免费| 国产精品久久久久av| 亚洲天堂男人| 1024亚洲| 欧美一区二区在线免费观看| 国产精品久久久久久五月尺| 欧美日韩一二区| 亚洲福利精品| 欧美午夜精品一区| 国产精品va在线| 亚洲一二三区在线观看| 一区二区欧美日韩| 欧美在线视频免费观看| 国产日韩精品一区二区| 亚洲永久免费观看| 在线精品一区| 国产午夜亚洲精品羞羞网站 | 国产精品一区免费在线观看| 久久riav二区三区| 亚洲图片在线观看| 国产精品一二三四区| 亚洲婷婷在线| 欧美四级电影网站| 亚洲国产成人在线视频| 欧美国产在线观看| 亚洲视频电影在线| 久久精品国产免费看久久精品| 国产精品主播| 欧美日韩国产色综合一二三四 | 久久大香伊蕉在人线观看热2| 欧美激情女人20p| 亚洲自拍偷拍一区| 亚洲国产日韩欧美一区二区三区| 欧美日韩成人激情| 欧美不卡在线| 欧美视频在线观看一区二区| 欧美日韩黄视频| 免费观看久久久4p| 亚洲视频二区| 亚洲特色特黄| 亚洲欧洲精品成人久久奇米网| 久久免费国产精品| 一本色道久久综合亚洲91| 国产欧美在线| 欧美电影在线播放| 欧美午夜久久| 久久人人精品| 欧美另类高清视频在线| 欧美亚洲综合在线| 欧美护士18xxxxhd| 久久se精品一区精品二区| 毛片精品免费在线观看| 小黄鸭精品aⅴ导航网站入口| 噜噜噜噜噜久久久久久91 | 一区二区日韩伦理片| 亚久久调教视频| 一区二区高清视频| 欧美在线亚洲在线| 亚洲一区久久久| 美女国产一区| 久久久久久久一区| 欧美三级电影一区| 亚洲高清久久久| 国产欧美一区二区三区沐欲| 国产一区日韩一区| 久久九九免费| 欧美日韩综合一区| 欧美国产日韩视频| 国内精品模特av私拍在线观看| 亚洲精品在线二区| 亚洲国产美女久久久久| 性欧美xxxx大乳国产app| 亚洲视频专区在线| 欧美高清视频www夜色资源网| 久久久久国产精品一区三寸| 国产精品扒开腿做爽爽爽视频 | 性做久久久久久| 欧美日韩免费观看中文| 91久久在线播放| 亚洲国产成人高清精品| 久久精品2019中文字幕| 久久大香伊蕉在人线观看热2| 欧美图区在线视频| 91久久精品国产91久久性色| 在线观看中文字幕不卡| 久久精品在线免费观看| 欧美一区三区二区在线观看| 国产精品婷婷午夜在线观看| av不卡在线观看| 亚洲视频欧美视频| 欧美日韩在线综合| 宅男66日本亚洲欧美视频| 亚洲一区二区三区高清不卡| 欧美日韩成人综合天天影院| 亚洲精品之草原avav久久| 一本色道久久| 国产精品国产三级国产普通话蜜臀| 日韩一级精品| 亚洲一区二区三区精品在线观看 | 久久青草福利网站| 欧美成人免费在线视频| 在线观看一区视频| 欧美成人精品在线| 999亚洲国产精| 欧美一区二区精品| 国模私拍视频一区| 免费一级欧美片在线播放| 亚洲精品久久7777| 亚洲制服欧美中文字幕中文字幕| 国产精品三上| 久久久久久高潮国产精品视| 欧美黑人国产人伦爽爽爽| 亚洲毛片播放| 国产精品一区二区欧美| 久久男人资源视频| 99精品国产在热久久下载| 久久国产手机看片| 亚洲电影第三页| 欧美日本精品一区二区三区| 亚洲女与黑人做爰| 看欧美日韩国产| 亚洲视屏在线播放| 在线观看中文字幕亚洲| 国产精品理论片|