【C/C++】回溯經典演算法之-->八皇后問題
阿新 • • 發佈:2018-12-26
一、八皇后問題
八皇后問題,是一個古老而著名的問題,是回溯演算法的典型案例。該問題是國際西洋棋棋手馬克斯·貝瑟爾於1848年提出:在8×8格的國際象棋上擺放八個皇后,使其不能互相攻擊,即任意兩個皇后都不能處於同一行、同一列或同一斜線上,問有多少種擺法。高斯認為有76種方案。1854年在柏林的象棋雜誌上不同的作者發表了40種不同的解,後來有人用圖論的方法解出92種結果。
二、問題分析
整體思路:
建立一個全域性變數的二維陣列chess;
並初始化全為0
一行一行開始放皇后;
若存在相互攻擊,則皇后向右移一列
若不存在攻擊,進行下一行皇后的放置(這裡要用到遞迴)
要點:
(1)國際象棋的格數
國際像是是8*8,因此,如果放置八個皇后,那麼每一行都有一個
(2)問題具體化
利用二維陣列,用1來代表皇后,其他為0
(3)皇后的放置方法
利用迴圈,判斷位置是否可以放置皇后,若可以,則放置(將其置1)
三、程式碼實現
程式碼塊:
#include<stdio.h> #include<windows.h> #define N 8 //可以根據N來修改棋盤的格數 int count = 0;//設定一個計數器 int chess[N][N] = {0};//用於存放棋盤的二維陣列 void print()//列印函式 { int i = 0; int j = 0; printf("*****************************************\n"); for(i = 0; i<N ;i++) { for(j = 0; j<N ; j++) { printf("%d ",chess[i][j]); } printf("\n"); } printf("*****************************************\n"); } //判斷是否會互吃 //關鍵條件 //返回1 表示存在互吃 //返回0 表示正常 int check(int i, int j)//i = 7,j = 4 { if(i == 0) return 0;//表示正常 int k = 0; for(k = 0; k<i ; k++) { if(chess[k][j] == 1)//(0,4)(1,4)... return 1; } for( int s = 0,k = j+1; k<N ;k++) { //(7,4)(6,5),(5,6),(4,7) if(chess[i-s-1][k] == 1)//(0,11),(1,10),(2,9),(3,8),(4,7) return 1; s++; } for(k = 0; k<j ;k++) { if(chess[i-k-1][j-k-1] == 1)//(6,3)(5,2)(4,1)(3,0) return 1; } for(k = 0; k<N ; k++) { if(chess[k][j]==1) return 1; } return 0; } //判斷棋盤上是否有一行存在沒有皇后的情況 //返回0 ,表示棋盤正常(每一行都有皇后) //返回1 ,表示棋盤有錯 int check_all() { int i = 0; int j = 0; int flag = 0; for(i = 0; i<N ;i++) { flag = 0; for(j = 0; j<N ; j++) { if(chess[i][j]==1) { flag = 1; break; } } if(flag == 0) return 1;//有錯 } return 0; } //檢查某一行是否存在皇后 //返回0 表示存在 //返回1 表示沒皇后 int check_line(int line) { if(line==0) return 0; int k = 0; int s = 0; int flag = 1; for(s = 0; s<line-1 ; s++) { flag = 1; for(k = 0; k<N ;k++) { if(chess[s][k]==1) flag = 0; } if(flag==1) return 1; } return 0; } //遞迴的主要演算法 void queen(int i,int j) { //符合,置一,進入下一行 if(check_line(i)==1)//若該行有皇后,返回 return ; if((i==(N-1)))//若此時是最後一行 { if(check(i,j)==0)//當最後一行的皇后可以放下(表示可以成功放置) { chess[i][j] = 1;//將該位置1,表示皇后 print();//列印 count++;//計數器+1 } } if(check(i,j)==0)//當可以放皇后時 { chess[i][j] = 1;//放入 //print(); //Sleep(1000); queen(i+1,0);//進行下一行的皇后放置 } if(j==N)//如果j等於列數,表明越界,返回 return ; chess[i][j] = 0;//將該位置0 //print(); //Sleep(500); //不符合,置零,右諾 queen(i,j+1);//將該行皇后右移一位 } int main(void) { queen(0,0); printf("\ncount = %d\n",count); return 0; }