<output id="qn6qe"></output>

    1. <output id="qn6qe"><tt id="qn6qe"></tt></output>
    2. <strike id="qn6qe"></strike>

      亚洲 日本 欧洲 欧美 视频,日韩中文字幕有码av,一本一道av中文字幕无码,国产线播放免费人成视频播放,人妻少妇偷人无码视频,日夜啪啪一区二区三区,国产尤物精品自在拍视频首页,久热这里只有精品12

      n皇后詳解及代碼實(shí)現(xiàn)/C++

      初衷

      這個(gè)學(xué)期開了算法課,要幾個(gè)關(guān)鍵算法思想的代碼實(shí)現(xiàn)。當(dāng)時(shí)感覺學(xué)的還可以了,也做了認(rèn)真的筆記。真正寫代碼的時(shí)候發(fā)現(xiàn)還是

      沒有完全掌握。網(wǎng)上關(guān)于這方面的資料也零零散散不是很全,致使走了不少彎路。今晚上實(shí)驗(yàn)成功驗(yàn)收了,感覺自己也收獲不小

      遂決定把算法實(shí)現(xiàn)的詳細(xì)思路記錄下來,一是自己坐下總結(jié)、另外也希望給當(dāng)時(shí)想我一樣找資料、搞算法的同學(xué)一些幫助。

      這中間我會(huì)盡最大可能的把問題描述清楚。

      這篇博文主要寫的是n皇后問題、后續(xù)還會(huì)加上背包問題(動(dòng)態(tài)規(guī)劃和分支界限)、旅行商問題等等。

       

      寫在前面

      不管什么問題、都是可以抽象的,對(duì)于任何問題,你總是可以找到幾個(gè)point,它們對(duì)問題全局有著決定性的作用,弄清楚看他們之間的內(nèi)在聯(lián)系;

      還有一個(gè)重要的方式就是找特例:對(duì)于一個(gè)無從下手的問題,可以舉幾個(gè)例子,找特例。通過幾個(gè)關(guān)鍵的point和特例,你就能容易的找出隱藏在問

      題背后的實(shí)質(zhì)。

      在這里我會(huì)給出這個(gè)問題的分析過程、而不會(huì)用成熟的理論來說明問題。如果你只想要代碼的話也可以直接copy。

       

      問題描述:

      一個(gè)n*n的棋盤,要在上面放n個(gè)皇后。規(guī)則:兩個(gè)皇后之間如果是同列、同行、同對(duì)角線它們會(huì)互相攻擊。也就是說:棋盤上的任意兩個(gè)皇后皇后

      不能為同列、同行、同對(duì)角線。

       

      問題分析

      對(duì)于這個(gè)問題、當(dāng)n不大的時(shí)候,可以用窮舉法實(shí)現(xiàn)。對(duì)于n皇后,每一行有n個(gè)位置可以放,一共n行。就會(huì)有n的n次方種情況。對(duì)于這些情況、再一一判斷是不是滿足情況。

      其實(shí)一個(gè)關(guān)鍵的點(diǎn)在于:什么時(shí)候判斷已經(jīng)放了皇后的棋盤是否滿足條件,大致可以分為兩種:

      1、等棋盤上放了n個(gè)皇后以后判斷

      2、放一個(gè)皇后判斷一次、對(duì)于特定的某一次,如果這種情況不滿足條件,那么以這種情況為基礎(chǔ)而生成的情況就不用再判斷了,他們都不會(huì)滿足條件。

      比如說:頭兩行有沖突,那么后面的不管怎么放,都沒有意義了,總會(huì)有沖突。

      如下圖:

       

       

      說明:這是四皇后的圖解,樹的每一層對(duì)應(yīng)棋盤的一層,樹的邊上的數(shù)字代表放在棋盤的位置,如:邊上的數(shù)字是3,則代表下一行的皇后位置

      是第三行,一次類推。可以看出,第一行有四個(gè)孩子,這是因?yàn)槠灞P上還沒有放任何皇后,所以第一行的每個(gè)位置都可以放而不會(huì)發(fā)生沖突。

      第二行就只有三個(gè)孩子因?yàn)檫@個(gè)時(shí)候第一行已經(jīng)有皇后,要保證不和第一樣的發(fā)生沖突,選擇的余地就變小了。一下情況一次類推。

      如果考慮全部情況的話,應(yīng)該每個(gè)節(jié)點(diǎn)都有四個(gè)孩子,然后再來判斷最終情況是否滿足情況,這會(huì)坐更多次數(shù)的判斷,導(dǎo)致低效率。

       

      上面兩種判斷法可以導(dǎo)致完全不同的算法效率:

      方法一判斷了每一種情況,其實(shí)就是窮舉法。方法二只判斷了一部分情況,對(duì)于那些沒有判斷的情況,是因?yàn)槲覀円呀?jīng)知道他們不可能成為解了,所以就

      沒有判斷的必要,可以節(jié)省大量的時(shí)間開支。

      (用稍微專業(yè)些的話就是在深度優(yōu)先遍歷解空間的時(shí)候每一步都判斷當(dāng)前狀態(tài)是否滿足條件,如不滿足就沒有就不再繼續(xù)往下遍歷,而是回溯)

       

      所以思路可以是這樣:在第一行放一個(gè)皇后(可以是任意位置),然后在第二行找一個(gè)可行的位置放置,在這個(gè)基礎(chǔ)上在第三行找一個(gè)沒有沖突的位置,如果

      發(fā)現(xiàn)某一行沒有地方可放了,那么修改它的上一行,(找到另外一個(gè)沒有沖突的位置),然后在繼續(xù)遍歷。(回溯)

      下面得考慮用什么樣的數(shù)據(jù)結(jié)構(gòu)來存儲(chǔ)結(jié)果:

      當(dāng)然,你可以用二維數(shù)組來存放,相當(dāng)于模擬了個(gè)棋盤,有皇后的位置存1,沒有皇后的位置存0,

      多數(shù)的做法是用一個(gè)數(shù)組來存放,(一維數(shù)組),下文會(huì)有提到。

       

      算法實(shí)現(xiàn)

      有了上面的分析后,再給出算法應(yīng)該就能比較好的理解了

      可以用遞歸和非遞歸來求解 :

      非遞歸算法:

      NQueens1(int n)
      { int k, n; extern int x[n]; k=0; x[k]=-1;
      while(k>=0)
      { x[k]=x[k]+1;
      while((x[k]<n) && (!Place(k)) x[k]=x[k]+1;  //如果當(dāng)前列不滿足情況,則判斷下一列
      if(x[k]<n)         //如果是上文while中的第二個(gè)條件不滿足而退出while循環(huán),也就是說找到了可以放置的位置
      { if(k<n-1) { k=k+1; x[k]=-1; }    //判斷當(dāng)前行是不是最后一行,如果是最后一行則表明已經(jīng)找到結(jié)果,打印結(jié)果
      else printf(x[0:n-1]);
      }
      else k=k-1;      //上文中while因?yàn)榈谝粋€(gè)條件不滿足而退出while循環(huán),在這行里沒有滿足條件的列,那么退回上一行重新選擇滿足
                        //條件的的列(回溯)
      }
      }


      代碼說明:K表示行數(shù),數(shù)組元素X[K]的值表示第K行的皇后位置,比如X[3]=2,表示第3行皇后的位置是2. 

      place()是判斷當(dāng)前位置是否滿足條件的函數(shù),如果滿足條件返回真,不滿足為假。從循環(huán)可知,如果當(dāng)前位置不可行,則判斷下一列:X[k]=X[k]+1,由于遞歸和非遞歸都會(huì)用到這個(gè)函數(shù),將在下面提到。

       有人可能注意到X[k]的初始值為-1,是因?yàn)閷?duì)于每一行程序都要從第一個(gè)位置(第一列)判斷,如果不滿足再往后,對(duì)于每一列的處理

      是從第一個(gè)while循環(huán)里開始的,里面的X[k]=X[k]+1,使得第一次判斷的是第一列。

      遞歸算法:

      NQueens2(int k)
      { extern int x[n];
      x[k]=-1;
      while(1)
      { x[k]=x[k]+1;
      while((x[k]<n)&&(!Place(k)) x[k]=x[k]+1;
      if(x[k]<n)
      { if(k<n-1) NQueens2(k+1);      //如果還沒找到最終解,則遞歸調(diào)用算法,判斷下一行(K+1)
      else printf(x[0:n-1]);
      }
      else return;
      }
      }

       

      對(duì)于兩個(gè)函數(shù)中都用到的place()函數(shù):

      int Place(int k) 
      { int i; extern int x[n];
      for(i=0; i<k-1; i++)
      if( (x[i]==x[k-1]) || (abs(x[i]-x[k-1])==abs(i-k+1)) )
      return false=0;
      return true=1;
      }

      傳入?yún)?shù)是K(行數(shù)),還引入數(shù)組X[n],這樣就能知道從第一行到第k行的皇后位置,(上文中說說x[k]這個(gè)數(shù)組是存放皇后位置的)

      要判斷第k行的x[k]列是否滿足條件,只要用k前的每一行來和它相比較,只要有其中的一行不滿足條件,就返回假。

      (x[i]==x[k-1])表示他們?cè)谕涣校?span data-mce-="">(abs(x[i]-x[k-1])==abs(i-k+1)表示他們?cè)谕粚?duì)角線


      算法實(shí)現(xiàn)代碼 (遞歸實(shí)現(xiàn))

       

      #include<fstream>
      #include<iostream>

      std::ofstream fout("queenoo.txt");

      /**//* 記錄當(dāng)前的放置方案 */
      int *x;
      /**//* 皇后的個(gè)數(shù)N 和 方案數(shù)目 */
      int n,sum=0;
      /**//* 檢查參數(shù)所指示的這一行皇后放置方案是否滿足要求 */
      int Place(int);
      /**//* 遞歸方法求取皇后放置方案*/
      void Queen1(void);
      /**//* 用戶遞歸求取皇后放置方案的遞歸方法 */
      void TraceBack(int);
      /**//* 打印當(dāng)前成功的放置方案 */
      void PrintMethod(void);

      int main()
      {
      using namespace std;
      long start,stop;
      cout<<"input n 輸入皇后個(gè)數(shù) :";
      cin>>n;

      x=(int *)malloc(sizeof(int)*n);
      time(&start);/**//*記錄開始時(shí)間*/
      Queen1();
      time(&stop);/**//*記錄結(jié)束時(shí)間*/
      cout<<"一共的方案數(shù)為:"<<sum<<"\n";
      cout<<"共花時(shí)間:"<<(int(stop-start))<<"\n";
      fout<< "一共的方案數(shù)為:"<<sum<<"\n";
      fout<< cout<<"共花時(shí)間:"<<((stop-start))<<"\n";

      }

      int Place(int r)
      {
      int i;
      for(i=0;i<r;i++){
      if(x[r]==x[i] || abs(r-i)==abs(x[r]-x[i]))
      return 0;
      }
      return 1;
      }

      void TraceBack(int r)
      {
      int i;
      if(r>=n){
      PrintMethod();
      sum++;
      /**//* PrintMethod(); */
      }else{
      for(i=0;i<n;i++){
      x[r]=i;
      if(Place(r)) TraceBack(r+1);
      }
      }
      }

      void PrintMethod(void)
      {
      int i,j;
      std::cout<<""<<sum<<"個(gè)方案\n";
      fout<<""<<sum<<"個(gè)方案\n";
      for(i=0;i<n;i++){
      for(j=0;j<n;j++){
      if(j==x[i]) std::cout<<"1",fout<<"1";
      else std::cout<<"0",fout<<"0";
      }
      std::cout<<"\n";
      fout<<"\n";
      }
      }

      void Queen1(void)
      {
      TraceBack(0);
      }

      以上代碼cfree5編譯通過。

      代碼把實(shí)驗(yàn)結(jié)果輸入到文件“queenoo.txt”中,路徑就在編譯器安裝路徑中,和執(zhí)行代碼位于同一目錄。

      非遞歸代碼類似,就沒寫出來


      后記

      解決八皇后問題用到的是一種稱為回溯的方法,在上面的分析過程中就體現(xiàn)了這種思想,在深度優(yōu)先遍歷解空間的時(shí)候加上判斷

      條件,只有符合條件的,才繼續(xù)往下遍歷。任何一種理論的產(chǎn)生都是先有實(shí)踐環(huán)節(jié)的,只有在實(shí)踐正確的情況下,才能總結(jié)出理論

      而很多算法書都是現(xiàn)給出里論,再給實(shí)例,其實(shí)這不是一種好的學(xué)習(xí)方式,這中間學(xué)習(xí)者少了許多思考、推導(dǎo)的過程,而這過程恰恰

      就是理論的雛形,忽視了這個(gè)關(guān)鍵的作用,只是被動(dòng)的的接受算法思想而不知道算法是怎樣產(chǎn)生的,不知其所以然,這樣學(xué)起來自然就

      不透徹而且很難掌握。

      所以在講皇后問題的時(shí)候,并沒有開篇就講什么是回溯法,回溯法的細(xì)想,如何運(yùn)用回溯法等等。而是用原始的思維去思考解決問題之道,

      等接觸回溯法時(shí)才恍然,啊、、這就是回溯法。那時(shí)候?qū)τ诶碚摰膶W(xué)習(xí)就能加深對(duì)算法思想的理解,自己在加以思考分析,就能比較好的

      掌握算法。


       

      以上博文如有錯(cuò)誤還望各位神仙大牛指正,在下感激不盡


      關(guān)于上文中提到的回溯法,會(huì)在下一篇博文中有詳細(xì)說明,歡迎關(guān)注


      如有轉(zhuǎn)載請(qǐng)注明出處:http://www.rzrgm.cn/yanlingyin/

      一條魚@博客園 2011-12-19

       

       

       

      posted @ 2011-12-19 10:51  Geek_Ling  閱讀(20440)  評(píng)論(1)    收藏  舉報(bào)
      主站蜘蛛池模板: 久艹视频免费看| 欧洲免费一区二区三区视频| 国产亚洲精品AA片在线爽| 国产久久热这里只有精品| 国产sm调教折磨视频| 丰满人妻一区二区三区无码AV| 丰满少妇人妻久久久久久| 亚洲AV无码破坏版在线观看| 国产日韩一区二区三区在线观看| 午夜福利免费区在线观看| 灵宝市| 一区二区不卡99精品日韩| 陵川县| 国产精品视频中文字幕| 日韩中文字幕人妻精品| 疯狂做受XXXX高潮国产| 国产日韩AV免费无码一区二区三区| 成人白浆一区二区三区在线观看| 在线中文字幕国产一区| 免费人妻无码不卡中文18禁| 亚洲大尺度无码无码专线| 国产精品办公室沙发| 伊人激情av一区二区三区| 无码日韩做暖暖大全免费不卡| 日韩有码中文字幕av| 97精品尹人久久大香线蕉| 狠狠综合久久综合88亚洲| 国产精品v片在线观看不卡| 国产精品涩涩涩视频网站| 国产主播精品福利午夜二区| 丰满人妻被黑人连续中出| 国产一区国产精品自拍| 97欧美精品系列一区二区| 国产精品亚洲一区二区z| 国产69精品久久久久久妇女迅雷| 国产私拍福利精品视频| 中文人妻| 国产在线观看免费观看| 四虎影视一区二区精品| 国产精品疯狂输出jk草莓视频| 精品剧情V国产在线观看|