八皇后(c++啓發式函數求解)

八皇后問題是回溯算法的典型案例,在回溯法中,經常是盲目搜索,耗費過多的搜索時間。在本次實驗中,使用了啓發式搜索,搜索時不是任取一個分支,而是選擇最佳的分支往下搜索。經過定義狀態空間、操做規則、搜索策略,咱們能夠清晰快速地獲得原問題的一個解。ios

八皇后問題是一個以國際象棋爲背景的問題:如何可以在 8×8 的國際象棋棋盤上放置八個皇后,使得任何一個皇后都沒法直接吃掉其餘的皇后?爲了達到此目的,任兩個皇后都不能處於同一條橫行、縱行或斜線上。經過計算機編程,咱們能夠快速地求出問題的解。算法

狀態空間

(i,C[i]), i = 0,1,…,7; (i,C[i])表示第i行的皇后放置在第C[i]列。 初始狀態爲C[i] = -1, i = 0,1,…,7;表示全部行都不放置皇后。 目標狀態爲C[i] != -1, i = 0,1,…,7;表示全部行都已經放置了皇后。

操做規則



第一個皇后放在第一行; 第二個皇后放在第二行且不與第一個皇后在同一列或對角線的空格上; …… 第i個皇后放在第i行且不與前面i-1個皇后在同一列或對角線的空格上。

搜索策略

因爲在某一步放置某個皇后時,可能有多個空格能夠使用,因此定義啓發式函數:

   fx = 剩下未放行中可以用來放皇后的空格數

若是第i行的皇后放在第j列合法,計算啓發式函數的值fx(i,j)。計算出第i行全部空格的fx後,將第i個皇后放到第i行中那個與前面i-1個皇后不在同一列或對角線上且fx值最大的空格中(相同時取第一個)。 若是當前策略沒法求解,則回溯至上一步,選擇fx值次大的空格放置皇后,依次類推,直至找到一個合法的解。
#include<stdio.h> #include <cstdio> #include<string> #include<math.h> #include<stdlib.h> #include<set> #include<map> #include<vector> #include<queue> #include<string.h> #include<algorithm> #include<iostream> #include<time.h> #include<list>
using namespace std; const int n=8; int c[8];  //c[i]表示第i行的皇后放在第c[i]列
int fx[8][8];  //fx[i][j]表示在i行j列放置皇后後,剩下行中能夠放Q的空格數
int ansflag=0; //標記是否已經找到答案
int vis[3][16];  //vis[0][j]表示第j列有無皇后,vis[1][i+j]表示對角線/上的和相同),vis[2][i-j+n]表示對角線\上的差相同,+n避免負數 //啓發式函數f():找到剩下行能夠放Q的空格數
int f(int row) { int cnt=0; for(int i=row+1;i<n;i++) { for(int j=0;j<n;j++) { if(!vis[0][j]&&!vis[1][i+j]&&!vis[2][i-j+n]) cnt++; } } return cnt; } void search(int cur) { if(cur==n) ansflag++;  //全部行都合法的放置了Q,結束
    else { int flag=0;  //標誌該行是否能夠放置皇后
        for(int i=0;i<n;i++)  //對於cur行的每一個空格進行測試
 { if(!vis[0][i]&&!vis[1][cur+i]&&!vis[2][cur-i+n]) { flag=1;  //[cur][i]處能夠放置Q
                 c[cur]=i; vis[0][i]=vis[1][cur+i]=vis[2][cur-i+n]=1; fx[cur][i]=f(cur);  //計算啓發式函數
                 vis[0][i]=vis[1][cur+i]=vis[2][cur-i+n]=0; } } if(flag)   //標誌該行能夠放置皇后
 { while(!ansflag) { int max=-1; int col=-1;     //記錄fx最大的列
                for(int i=0;i<n;i++) //找fx最大的列
 { if(fx[cur][i]>max) { max=fx[cur][i]; col=i; } } if(max==-1) //在本行任一空格放置皇后都沒法求解,回溯
 { fx[cur-1][c[cur-1]]=-1;  //將原來的最大值置爲-1,那麼下一次回溯找的是次大值。
                    return; } c[cur]=col;   //找到fx最大的列,放置皇后,搜索下一行。
                vis[0][col]=vis[1][cur+col]=vis[2][cur-col+n]=1; search(cur+1); vis[0][col]=vis[1][cur+col]=vis[2][cur-col+n]=0; } } else   //標誌該行不能夠放置皇后
            fx[cur-1][c[cur-1]]=-1; } } int main() { memset(c,-1,sizeof(c)); memset(fx,-1,sizeof(fx)); memset(vis,0,sizeof(vis)); search(0); for(int i=0;i<n;i++) { for(int j=0;j<n;j++) { if(j==c[i]) cout<<"Q"<<' '; else cout<<"X"<<" "; } cout<<endl; } }

解對應的棋盤: 
Q X X X X X X X 
X X X X X Q X X 
X X X X X X X Q 
X X Q X X X X X 
X X X X X X Q X 
X X X Q X X X X 
X Q X X X X X X 
X X X X Q X X X編程

相關文章
相關標籤/搜索