• <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>
            隨筆 - 70  文章 - 160  trackbacks - 0

            公告:
            知識共享許可協(xié)議
            本博客采用知識共享署名 2.5 中國大陸許可協(xié)議進行許可。本博客版權(quán)歸作者所有,歡迎轉(zhuǎn)載,但未經(jīng)作者同意不得隨機刪除文章任何內(nèi)容,且在文章頁面明顯位置給出原文連接,否則保留追究法律責(zé)任的權(quán)利。 具體操作方式可參考此處。如您有任何疑問或者授權(quán)方面的協(xié)商,請給我留言。

            常用鏈接

            留言簿(8)

            隨筆檔案

            文章檔案

            搜索

            •  

            積分與排名

            • 積分 - 179341
            • 排名 - 147

            最新評論

            閱讀排行榜

            評論排行榜

            軟件課講了這些問題,這次順便總結(jié)下。

             說白了也就是:遞歸,回溯,深搜或者廣搜。 

             1.漢諾塔 

             ////////////////////////////////////////////////
            /*
            漢諾塔
            題目:
            假設(shè)有A, B, C 3個軸,有n個直徑各不相同,
            從小到大依次編號為1,2,3,…,n的圓盤
            按照從小到大的順序疊放在A軸上?,F(xiàn)在要求
            將這n個圓盤移至C軸上并仍然按照同樣順序
            疊放,但圓盤移動時必須遵守下列規(guī)則:
            1.每次只能移動一個圓盤,它必須位于某個
              軸的頂部。
            2.圓盤可以插在A,B,C中任一軸上。
            3.任何時刻都不能將一個較大的圓盤壓在較小
              的圓盤之上。
            */
            /////////////////////////////////////////////// 

            經(jīng)典的問題,屬于遞歸的入門級問題,但是同樣不好分析,在n<=4以內(nèi)還可以模擬下漢諾塔的實現(xiàn),當(dāng)n>=5時就不太現(xiàn)實了,讓我們來看看漢諾塔當(dāng)圓盤個數(shù)n時有多少組解? 按照傳說來看:n=64,當(dāng)所有的金片都從梵天穿好的那根針上移到另外一根針上時,世界就將在一聲霹靂中消滅,而梵塔、廟宇和眾生也都將同歸于盡。 

             但是這畢竟是神話,不過當(dāng)把64個金片全部放到另外一根針時,確實要很長很長一段時間。 
            讓我們來看看需要多長時間。 
             首先,我們找出遞推關(guān)系: 
             f(n + 1) = 2*f(n) + 1 
             至于這個怎么得到的可以畫圖看看。 
             把遞推關(guān)系算出來后,也就是: 
             f(n) = 2^n-1 
             那么當(dāng)n=64時,是多少? 
             f(64)= 2^64-1=18446744073709551615   
            假如每秒鐘一次,共需多長時間呢?一年大約有 31536926 秒,計算表明移完這些金片需要5800多億年,比地球壽命還要長,事實上,世界、梵塔、廟宇和眾生都已經(jīng)灰飛煙滅。 

            好吧,說了那么多,還是步入正題。
            漢諾塔的實現(xiàn)有遞歸和非遞歸兩種情況,遞歸的很常見,也很簡單,非遞歸實際上就是二叉樹的中序遍歷。也可以認(rèn)為是棧的實現(xiàn)。
            遞歸的版本:
            /*遞歸實現(xiàn)*/
            #include 
            <iostream>
            using namespace std;
             
            //把n號圓盤從x移到y(tǒng),并打印出。
            void Move(int n, char x, char y)
            {
              cout
            << "" << n << "號圓盤從" << x << "移動到" << y << endl;
            }
             
            //把前n個通過b從a移到c
            void Hanoi(int n, char a, char b, char c)  
            {
                
            if(n == 1)
                    Move(
            1, a, c);
                
            else
                {
                    Hanoi(n
            -1, a, c, b);
                    Move(n, a, c);
                    Hanoi(n
            -1, b, a, c);
                }
            }
             
            int main()
            {
                
            int n;
                cout 
            << "輸入n的大小: ";
                cin 
            >> n;
                Hanoi(n, 
            'a''b''c');
                cout 
            << "Ok!" << endl << "By Tanky Woo." << endl;
                
            return 0;
            }

            非遞歸的版本有時間再補上。


            2.n皇后
            對于每一個ACMer,八皇后問題都是必經(jīng)之路。

             作為搜索類題目還是老問題: 

             1.邊界條件。 
             2.對每種情況都得遍歷到,可以用解答樹分析。 
             3.剪枝 http://www.wutianqi.com/?p=1341(搜索與剪枝)
             4.輔助空間的變化。回溯前和回溯后的變化。 
             如果不用輔助空間的回溯當(dāng)然就不需要注意輔助空間的問題了。 

            以下是n皇后的源碼: 

            /*
            *  n皇后問題
            *  Tanky Woo
            */
             
            #include 
            <iostream>
            using namespace std;
             
            int queen[100];
            int n;         // n皇后
            int tot = 0;   //解法種數(shù)
             
            // www.wutianqi.com
            void search(int cur)
            {
                
            if(cur == n)   //遞歸邊界。符合要求,輸出。
                {
                    tot
            ++;
                    
            for(int i=0; i<n; ++i)
                        cout 
            << queen[i] << " ";
                    cout 
            << endl;
                }
                
            else
                {
                    
            for(int i=0; i<n; ++i)
                    {
                        
            bool flag = 1;
                        queen[cur] 
            = i;    // 嘗試把第cur行的皇后放在第i列
                        for(int j=0; j<cur; ++j)    // 檢查是否和前面的皇后沖突
                            if(queen[cur] == queen[j]        // 同一列
                            || cur-queen[cur] == j-queen[j]    // 正對角線
                            || cur+queen[cur] == j+queen[j])   // 反對角線
                            {
                                flag 
            = 0;
                                
            break;
                            }
                        
            if(flag)
                            search(cur
            +1);    // 如果合法,繼續(xù)
                    }
                }
            }
             
            int main()
            {
                cout 
            << "輸入皇后個數(shù)n: ";
                cin 
            >> n;
                search(
            0);
                cout 
            << "共有" << tot << "種解." << endl << "By Tanky Woo." << endl;
                
            return 0;
            }

            對于這個問題,還可以用輔助空間來提高算法的效率: 增加輔助空間vis[][]來判斷是否有其他皇后已經(jīng)在列和對角線上。 
            #include <iostream>
            using namespace std;
             
            int queen[100];
            int n;         // n皇后
            int tot = 0;   //解法種數(shù)
             
             
            int vis[3][100];   // 輔助空間
            void search(int cur)
            {
                
            if(cur == n)   //遞歸邊界。符合要求,輸出。
                {
                    tot
            ++;
                    
            for(int i=0; i<n; ++i)
                        cout 
            << queen[i] << " ";
                    cout 
            << endl;
                }
                
            else
                {
                    
            for(int i=0; i<n; ++i)
                    {
                        
            if(!vis[0][i] && !vis[1][cur+i] && !vis[2][cur-i+n])
                        {
                            queen[cur] 
            = i;
                            vis[
            0][i] = vis[1][cur+i] = vis[2][cur-i+n] = 1;
                            search(cur
            +1);
                            vis[
            0][i] = vis[1][cur+i] = vis[2][cur-i+n] = 0;  //記住要變化來
                        }
                    }
                }
            }
             
             
            int main()
            {
                memset(vis, 
            0sizeof(vis));
                cout 
            << "輸入皇后個數(shù)n: ";
                cin 
            >> n;
                search(
            0);
                cout 
            << "共有" << tot << "種解." << endl << "By Tanky Woo." << endl;
                
            return 0;
            }


            3.跳馬問題: 
            據(jù)說此題證明可以用組合數(shù)學(xué)中的哈密頓環(huán)。
            組合數(shù)學(xué)確實博大精深,看過一段時間的組合數(shù)學(xué),感覺和實際聯(lián)系的很多,Orz.
            此題有兩種版本: 

             ①:給定一個N*N的棋盤,起始點在(0,0)處,要求求出有多少種方法,可以不重復(fù)的遍歷棋盤上所有的點。 
               規(guī)則:1.馬走日字
                       2.走過的點就不能再走了 

             此題和上面的n皇后類似,是標(biāo)準(zhǔn)的DFS。 
            分析:從起始點開始,每次遍歷八種方向,直到邊界條件,并輸出。 

            以下是跳馬問題一的源碼:

            /*馬跳棋盤問題*/
             
            #include 
            <iostream>
            using namespace std;
            const int N = 10;
            int a[N][N] = {0};
            int cnt = 0;
             
            void Horse(int a, int b, int t);
            // www.wutianqi.com
            int main()
            {
                
            int i = 0, j = 0, t = 1;
                a[i][j] 
            = t;
                Horse(i, j, step
            +1);
                cout 
            << cnt << endl;
                cout 
            << "By Tanky Woo.\n";
                
            return 0;
            }
            void Horse(int a, int b, int t)
            {

                int x[4={-2-112}, y[4= {-2-112};  
                
            if(t == N*N+1)  
                    cnt
            ++;
             
                
            for(int i=0; i<4++i)
                    
            for(int j=0; j<4++j)
                    {
                        
            if(x[i]==y[j] || x[i]==-y[j])  
                            continue;
                        
            if(a+x[i]>=0 && a+x[i]<&& b+y[j]>=0 && b+y[j]<&& board[a+x[i]][b+y[j]]==0)
                        {
                            a[a
            +x[i]][b+y[j]] = t;
                            Horse(a
            +x[i], b+y[j], t+1);
                            a[a
            +x[i]][b+y[j]] = 0;
                        }
                    }
            }
             


            第二個版本: ②:設(shè)有右圖所示的一個棋盤,在棋盤上的A點,有一個中國象棋的馬,并約定馬走的規(guī)則:
            規(guī)則:1. 馬走日字
                    2. 馬只能向右走。
            試找出所有從A到B的途徑。 
              

            此題也是OI上很有名的騎士問題。
            此題似乎比較適合BFS. 
            還沒嘗試過。 
             


             
            讓我再想想,好像還有八數(shù)碼和素數(shù)環(huán)問題沒寫。
            不過在HDOJ上遇到過一個素數(shù)環(huán)的題目:
            http://www.wutianqi.com/?p=1329
            有興趣可以做下。

            對于DFS和BFS更多的題目,可以在我博客右上角搜索欄里輸入DFS或BFS,會出來相應(yīng)題目。  

            posted on 2010-09-30 15:24 Tanky Woo 閱讀(2537) 評論(2)  編輯 收藏 引用

            FeedBack:
            # re: 漢諾塔,n皇后,跳馬問題匯總 2010-10-07 12:24 popeer
            hanoi的遞歸實現(xiàn)越搬號大的圓盤,越是費時間。

            我用程序試過了,從是把1,2,3,4這樣的小號翻來覆去的搬家,遞歸真苦惱。  回復(fù)  更多評論
              
            # re: 漢諾塔,n皇后,跳馬問題匯總[未登錄] 2010-10-07 12:49 Tanky Woo
            @popeer
            對。嚴(yán)蔚敏的《數(shù)據(jù)結(jié)構(gòu)》上好像有對n=4的模擬,似乎要10多步還是20步。反正挺多的。
            當(dāng)n>=5基本就很難模擬了,中間出錯一步全部就白費了。

            遞歸這種東西找的是相對關(guān)系,不要多想,否則會越想越糊涂。  回復(fù)  更多評論
              
            精品免费久久久久久久| 久久精品www| 一本一本久久a久久精品综合麻豆| 国产精品免费久久久久久久久| 久久国产V一级毛多内射| 性高湖久久久久久久久AAAAA| 久久99亚洲综合精品首页| 久久久久亚洲AV成人网人人网站 | 久久99国产精一区二区三区| 久久国产免费观看精品| 欧美日韩精品久久久久| 久久国语露脸国产精品电影| 蜜桃麻豆www久久| 亚洲国产成人久久一区WWW| 精品综合久久久久久97| 很黄很污的网站久久mimi色 | 久久精品亚洲欧美日韩久久| 狠狠色婷婷久久综合频道日韩| 91久久香蕉国产熟女线看| 伊人久久大香线蕉综合影院首页| 一本色道久久88加勒比—综合| 亚洲精品乱码久久久久久蜜桃图片| 日本久久久精品中文字幕| 久久久久无码精品国产| 久久久久综合中文字幕| 久久久国产精品福利免费 | 久久播电影网| 一本大道久久a久久精品综合| 久久综合给合久久国产免费| 欧美久久一区二区三区| 久久天天躁狠狠躁夜夜不卡| 国产精品久久久久9999| 99久久人妻无码精品系列| 丰满少妇人妻久久久久久| 一本色道久久88精品综合| 久久亚洲精品无码aⅴ大香| 午夜福利91久久福利| 色婷婷久久综合中文久久一本| 久久e热在这里只有国产中文精品99 | 精品无码久久久久久久动漫| 奇米综合四色77777久久|