国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 編程 > C++ > 正文

C++基于回溯法解決八皇后問題示例

2020-05-23 13:36:12
字體:
來源:轉載
供稿:網友

本文實例講述了C++基于回溯法解決八皇后問題的方法。分享給大家供大家參考,具體如下:

回溯法的基本做法是搜索,或是一種組織得井井有條的,能避免不必要搜索的窮舉式搜索法。這種方法適用于解一些組合數相當大的問題。

回溯法在問題的解空間樹中,按深度優先策略,從根結點出發搜索解空間樹。算法搜索至解空間樹的任意一點時,先判斷該結點是否包含問題的解。如果肯定不包含,則跳過對該結點為根的子樹的搜索,逐層向其祖先結點回溯;否則,進入該子樹,繼續按深度優先策略搜索。

回溯法指導思想——走不通,就掉頭。設計過程:確定問題的解空間;確定結點的擴展規則;搜索。

n皇后問題

要在n*n的國際象棋棋盤中放n個皇后,使任意兩個皇后都不能互相吃掉。規則:皇后能吃掉同一行、同一列、同一對角線的任意棋子。求所有的解。n=8是就是著名的八皇后問題了。

設八個皇后為xi,分別在第i行(i=1,2,3,4……,8);

問題的解狀態:可以用(1,x1),(2,x2),……,(8,x8)表示8個皇后的位置;

由于行號固定,可簡單記為:(x1,x2,x3,x4,x5,x6,x7,x8);

問題的解空間:(x1,x2,x3,x4,x5,x6,x7,x8),1≤xi≤8(i=1,2,3,4……,8),共88個狀態;

約束條件:八個(1,x1),(2,x2) ,(3,x3),(4,x4) ,(5,x5), (6,x6) , (7,x7), (8,x8)不在同一行、同一列和同一對角線上。

盲目的枚舉算法:通過8重循環模擬搜索空間中的88個狀態,從中找出滿足約束條件的“答案狀態”。程序如下:

/* *作者:侯凱 *說明:八皇后——盲目迭代法 *日期:2013-12-18 */#include <iostream>using namespace std;bool check_1(int a[],int n){for(int i=2;i<=n;i++){ for(int j=1;j<=i-1;j++) {  if ((a[i]==a[j])||(abs(a[i]-a[j])==i-j))  {   return false;  } }}return true;//不沖突}void queens_1(){ int a[9]; int count = 0; for(a[1]=1;a[1]<=8;a[1]++) {  for(a[2]=1;a[2]<=8;a[2]++)  {   for(a[3]=1;a[3]<=8;a[3]++)   {    for(a[4]=1;a[4]<=8;a[4]++)    {     for(a[5]=1;a[5]<=8;a[5]++)     {      for(a[6]=1;a[6]<=8;a[6]++)      {       for(a[7]=1;a[7]<=8;a[7]++)       {        for(a[8]=1;a[8]<=8;a[8]++)        {         if(!check_1(a,8))           continue;         else         {          for(int i=1;i<=8;i++)           {           cout<<a[i];          }          cout<<endl;          count++;         }        }       }      }     }    }   }  } } cout<<count<<endl;}void main(){ queens_1();}

程序思想比較簡單,最后可知共92種擺放方法。如果能夠排除那些沒有前途的狀態,會節約時間——回溯法(走不通,就回頭)。

bool check_2 (int a[ ],int n){//多次被調用,只需一重循環  for(int i=1;i<=n-1;i++) {  if((abs(a[i]-a[n])==n-i)||(a[i]==a[n]))   return false; }   return true;}void queens_2(){ int a[9]; int count = 0; for(a[1]=1;a[1]<=8;a[1]++) {  for(a[2]=1;a[2]<=8;a[2]++)  {   if (!check_2(a,2)) continue;   for(a[3]=1;a[3]<=8;a[3]++)   {    if (!check_2(a,3)) continue;    for(a[4]=1;a[4]<=8;a[4]++)    {     if (!check_2(a,4)) continue;     for(a[5]=1;a[5]<=8;a[5]++)     {      if (!check_2(a,5)) continue;      for(a[6]=1;a[6]<=8;a[6]++)      {       if (!check_2(a,6)) continue;       for(a[7]=1;a[7]<=8;a[7]++)       {        if (!check_2(a,7)) continue;        for(a[8]=1;a[8]<=8;a[8]++)        {         if (!check_2(a,8))           continue;         else         {          for(int i=1;i<=8;i++)           {           cout<<a[i];          }          cout<<endl;          count++;         }        }       }      }     }    }   }  } } cout<<count<<endl;}void main(){ queens_2();}

n此算法可讀性很好,體現了“回溯”。但它只針對八皇后問題,解決任意的n皇后問題還要修改程序結構。如果要解決n皇后的問題,就需要將n作為參數傳遞給函數,函數需要重寫來實現回溯(不能采用級聯的for循環,n不確定);從另一方面,程序中出現了大量的for循環,而且for中的函數結構很相似,自然想到的是遞歸迭代回溯。這就是回溯比較常用的兩種實現方法:非遞歸回溯和遞歸回溯。

非遞歸回溯的程序實現:

void backdate (int n){  int count = 0; int a[100]; int k = 1; a[1]=0;  while(k>0) {  a[k]=a[k]+1;//對應for循環的1~n  while((a[k]<=n)&&(!check_2(a,k)))//搜索第k個皇后位置  {   a[k]=a[k]+1;  }  if(a[k]<=n)//找到了合理的位置  {   if(k==n )   {//找到一組解    for(int i=1;i<=8;i++)     {     cout<<a[i];    }    cout<<endl;    count++;   }    else    {    k=k+1;//繼續為第k+1個皇后找到位置,對應下一級for循環     a[k]=0;//下一個皇后一定要從頭開始搜索   }  }  else  {   k=k-1;//回溯,對應執行外內層for循環回到更上層   } } cout<<count<<endl;}void main(){ backdate(8);}

這樣也可以得到,8皇后問題的92中結果。更簡單、可讀的方法是采用遞歸的方式,如下:

int a[100], n, count;void backtrack(int k){ if (k>n)//找到解 {  for(int i=1;i<=8;i++)   {   cout<<a[i];  }  cout<<endl;  count++; } else {  for (int i = 1;i <=n; i++)  {   a[k] = i;   if (check_2(a,k) == 1)   {backtrack(k+1);}  } }}void main(){ n=8,count=0; backtrack(1); cout<<count<<endl;}

可見,遞歸調用大大減少了代碼量,也增加了程序的可讀性。給出其中的一個解,如下:

C++,回溯法,八皇后問題

希望本文所述對大家C++程序設計有所幫助。


發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
主站蜘蛛池模板: 夏河县| 隆回县| 岚皋县| 清涧县| 东乡县| 峨山| 牙克石市| 灌云县| 广水市| 府谷县| 房山区| 泌阳县| 陵水| 原平市| 德惠市| 聂拉木县| 拉萨市| 阿坝| 丽水市| 斗六市| 文昌市| 饶平县| 阜新市| 民和| 福清市| 微山县| 名山县| 宁都县| 九龙坡区| 临潭县| 凌海市| 翼城县| 华容县| 江山市| 盘锦市| 莱阳市| 个旧市| 绥化市| 开封市| 舞阳县| 肇庆市|