1. 程式人生 > >八皇後(c++啟發式函數求解)

八皇後(c++啟發式函數求解)

bsp 進行 time cout class 操作 實驗 回溯 線上

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

八皇後問題是一個以國際象棋為背景的問題:如何能夠在 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

八皇後(c++啟發式函數求解)