八皇后问题经典解析
八皇后问题
八皇后问题,是一个古老而著名的问题,是回溯算法的典型例题。该问题是十九世纪著名的数学家高斯1850年提出:在8X8格的国际象棋上摆放八个皇后,使 其不能互相攻击,即任意两个皇后都不能处于同一行、同一列或同一斜线上,问有多少种摆法。 高斯认为有76种方案。1854年在柏林的象棋杂志上不同的作者发表了40种不同的解,后来有人用图论的方法解出92种结果。计算机发明后,有多种方法可 以解决此问题。
摘自百度百科
解题思路:深度搜索加记忆数组
*因为皇后不能处于同一行,同一列,同一斜线(即主对角线和副对角线),所以可以判断出8个皇后分别各占一行
*不妨假设从第一行开始,行数依次加一确定每一行皇后的位置,在下面的程序中cur代表行号,因为我们依次让
*行号加一,所以不会存在行号重叠的现象,接下来只需判断列数和对角线没有发生重叠即可,这里,我们用一个记
*忆状态的数组(vis[][])来存储列和对角线的状态,每次确定一个皇后的位置,首先判断其对应的列和对角线是否
*染色,如果没有染色,则该位置有效,并染色,这样就不会出现列和对角线重叠的问题.
下面重点讲解一下对角线,其原理可用下图说明:
(格子(i-j)的值标示了主对角线)
同理读者自行可以推出
(格子(i+j)的值标示了副对角线)
又因为主对角线的值有为负数的情况,所以我们在标记的时候应该加>=7的数,所有值都加了>=7所以标记的效果并没有改变
1 #include<iostream>
2 usingnamespace std;
3 bool vis[3][30];//记忆数组判断列,主对角线,副对角线是否被占
4 int ans=0;
5 void dfs(int cur)
6 {
7 if(cur==9)//如果当前行数超过8(表明八个皇后已经放好)则结果加一,返回继续递归
8 {
9 ans++;
10 return ;
11 }
12 //vis[0][i]判断列,vis[i][cur-i+8]判断主对角线,vis[2][cur+i]判断副对角线
13 for(int i=1;i<=8;i++)if(!vis[0][i]&&!vis[1][cur-i+8]&&!vis[2][cur+i])
14 {
15 vis[0][i]=vis[1][cur-i+8]=vis[2][cur+i]=true;
16 dfs(cur+1);//深度搜索
17 vis[0][i]=vis[1][cur-i+8]=vis[2][cur+i]=false;
18 }
19 }
20 int main()
21 {
22 dfs(1);//初始化cur为1,即从第一行开始
23 cout<<"有 "<<ans<<" 种结果."<<endl;
24 system("pause");
25 return0;
26 }
2 usingnamespace std;
3 bool vis[3][30];//记忆数组判断列,主对角线,副对角线是否被占
4 int ans=0;
5 void dfs(int cur)
6 {
7 if(cur==9)//如果当前行数超过8(表明八个皇后已经放好)则结果加一,返回继续递归
8 {
9 ans++;
10 return ;
11 }
12 //vis[0][i]判断列,vis[i][cur-i+8]判断主对角线,vis[2][cur+i]判断副对角线
13 for(int i=1;i<=8;i++)if(!vis[0][i]&&!vis[1][cur-i+8]&&!vis[2][cur+i])
14 {
15 vis[0][i]=vis[1][cur-i+8]=vis[2][cur+i]=true;
16 dfs(cur+1);//深度搜索
17 vis[0][i]=vis[1][cur-i+8]=vis[2][cur+i]=false;
18 }
19 }
20 int main()
21 {
22 dfs(1);//初始化cur为1,即从第一行开始
23 cout<<"有 "<<ans<<" 种结果."<<endl;
24 system("pause");
25 return0;
26 }