参考:
韩金轮-AI-实验2
一、实验目的
- 求解约束满足问题;
- 使用回溯搜索算法求解八皇后问题。
二、实验平台
课程实训平台:头歌实践教学平台
三、实验内容
-
实训内容:2-4 第六章 约束满足问题
-
八皇后问题:使用回溯搜索算法解决八皇后问题并求出共有多少种算法;
四、实验步骤
1.算法介绍-回溯搜索算法
回溯是搜索算法中的一种控制策略。
基本思想:为了求得问题的解,先选择某一种可能情况向前探索,在探索过程中,一旦发现原来的选择是错误的,就退回一步重新选择,继续向前探索,如此反复进行,直至得到解或证明无解。
2.编程
在右侧编辑器中完成void searchh(int i)函数,求出八皇后问题共有多少种算法
(1)算法思想-DFS:
①形参i
searchh函数中的形参i:
- 在搜索树中表示第i层节点;
- 在八皇后问题中,表示第i行
②递归终止判断
终止条件i>8:
- 在搜索树中层数大于8时:为叶节点的子节点(NULL),应当向上回溯,不再向下一层递归;
- 在八皇后问题中:已经考察完所有的行,应当把可行方案加一,然后返回;
③扩展当前层/行
在八皇后问题中,扩展第i行:
- 对于第i行:考察这一行的第1到8列(j);
- 判断第j列_能否可以放置_:
- 第j列无其他Q:!b[j];
- 第i行第j列所在的对角线无其他Q:!c[i+j];
- 第i行第j列所在的反对角线无其他Q:!d[i-j+7];
- 放置:
- 第j列、第i行第j列所在的对角线、反对角线标记为已放Q:b[j]=c[i+j]=d[i-j+7]=1;
- 棋盘第i行第j列标记放置:a[i]=j;
- 递归考察下一行:
- searchh(i+1)
- 考察完当前行i的第j列后,恢复现场,继续考虑其他的列j++;
- 恢复现场:b[j]=c[i+j]=d[i-j+7]=0;
- 当前行a[i]=0;
(2)实现searchh(int i)
#include<iostream>
using namespace std;
int a[9];
int b[9]={0};
int c[16]={0};
int d[16]={0};
int sum=0;
void searchh(int i)
{
if(i>8) {
sum++;
return;
}
for(int j=1;j<=8;j++)
{
if((!b[j])&&(!c[i+j])&&(!d[i-j+7]))//每个皇后都有八个位置(列)可以试放
{
/********** Begin **********/
a[i]=j;
b[j]=c[i+j]=d[i-j+7]=1;
searchh(i+1);
b[j]=c[i+j]=d[i-j+7]=0;
a[i]=0;
/********** End **********/
}
}
}
(3)递归终止判断放在Begin,End里
把代码都写在要求的Begin,End里面:
i为8的时候,即不再递归考察下一行;
#include<iostream>
using namespace std;
int a[9];
int b[9]={0};
int c[16]={0};
int d[16]={0};
int sum=0;
void searchh(int i)
{
for(int j=1;j<=8;j++)
{
if((!b[j])&&(!c[i+j])&&(!d[i-j+7]))//每个皇后都有八个位置(列)可以试放
{
/********** Begin **********/
if(i==8){
sum++;
}
else{
a[i]=j;
b[j]=c[i+j]=d[i-j+7]=1;
searchh(i+1);
b[j]=c[i+j]=d[i-j+7]=0;
a[i]=0;
}
/********** End **********/
}
}
}
3.n皇后问题(1≤n≤9)
(1)题目
(2)编程
需注意的是,下面的数组(棋盘)是从0到n-1;而头歌平台上的是1到n;
#include <iostream>
using namespace std;
const int N=20;
int n;
char g[N][N];
int col[N],dg[N],udg[N];
int sum;
void dfs(int u){
if(u == n){
for(int i=0;i<n;i++) puts(g[i]);
puts("");
sum++;
return;
}
for(int i=0;i<n;i++){
if(!col[i] && !dg[u+i] && !udg[n-u+i]){
col[i]=dg[u+i]=udg[n-u+i]=1;
g[u][i]='Q';
dfs(u+1);
g[u][i]='.';
col[i]=dg[u+i]=udg[n-u+i]=0;
}
}
}
int main(){
scanf("%d",&n);
for(int i=0;i<n;i++){
for(int j=0;j<n;j++){
g[i][j]='.';
}
}
dfs(0);
printf("%d",sum);
}
(3)运行测试
①n=4
②n=8
方案数为92,太多;把上面的输出棋盘部分的代码注释掉了;