最近在重新看递归,准备复试,刚好看到八皇后问题。
主要思路是画出8*8的棋盘,可放皇后位置为0,否则为1。因为正确解一定是每一行都有一个皇后,所以以行按深度优先搜索分解问题。从(0,0)开始放皇后,搜索下一行第一个0,放置皇后,相应不可放位置都置1,再在下一行搜索第一个0...如果遇到在第7行(从第0行开始)仍有0可以放皇后,则找到解;否则返回上一行,恢复棋盘,找该行第二个0放置皇后,继续往下搜索,多次返回后该行的所有0也都被搜索完毕,则再返回上一行进行类似搜索。
遇到的问题主要有两大方面:
1.循环实现放皇后对相应方格的置1操作,要注意循环条件,考虑4种情况。
2.递归中的循环逻辑。见代码注释。
另外,由于进入递归起始的位置是给定的(0,0),需要在主函数内循环实现对第0行所有位置的递归求解。这一点也是看了好久,通过递归层数计数才发现。
#include <iostream>
#include <stdio.h>
using namespace std;
//八皇后问题
int table[8][8] = {};
int count = 0;
typedef enum arg
{CLR,SET} ctr;
int countdg;//递归层数计数
void SetRowLineDiag(int x,int y,ctr arg);
void EightQ(int x,int y);
void copyArray(int (*array_temp)[8],int (*table)[8]); //数组指针
void coutArray(int (*array)[8]);
int main()
{
int i;
int array_temp[8][8]={};
copyArray(array_temp,table);
for(i=0;i<8;i++)
{
copyArray(table,array_temp); //要注意返回后对棋盘的恢复
EightQ(0,i);
}
cout<<count<<endl;
return 0;
}
void SetRowLineDiag(int x,int y,ctr arg) //x为行,y为列
/*皇后所在位置,相关位置置一或清零*/
{
int i,j;
for(i=0;i<8;i++)
{
table[i][y] = arg; //改列
table[x][i] = arg; //改行
}
int s=x+y;
if(s>=7)//左斜线
{
for(i=7;i>=s-7;i--)
{
j=s-i;
table[i][j] = arg;
}
}
else if(s<7)
{
for(j=0;j<=s;j++)
{
i=s-j;
table[i][j] = arg;
}
}
if(x>=y)//右斜线
{
for(i=x-y,j=0;i<=7;i++,j++)
table[i][j] = arg;
}
else
{
for(j=y-x,i=0;j<=7;i++,j++)
table[i][j] = arg;
}
}
void copyArray(int (*array_temp)[8],int (*table)[8]) //数组指针
{
int i,j;
for(i=0;i<8;i++)
{
for(j=0;j<8;j++)
array_temp[i][j] = table[i][j];
}
}
void coutArray(int (*array)[8])//输出棋盘
{
int i,j;
for(i=0;i<8;i++)
{
for(j=0;j<8;j++)
cout<<array[i][j];
cout<<endl;
}
cout<<endl;
}
void EightQ(int x,int y) //逐行进行搜索
{
if(x==7 && y<8)//得到解,计数加一
{
count++;
// getchar();
return ;
}
else if(y>=8)//已超边界,无解
return ;
// cout<<countdg++<<endl; //递归层数
SetRowLineDiag(x,y,SET); //由上一层指定的该层皇后位置,相应位置置1
int array_temp[8][8];
copyArray(array_temp,table);//保存该层棋盘,即下一层初始棋盘
// coutArray(array_temp);
int j=0;
while(j<=7) //扫描下一层
{
while(table[x+1][j]==1 && j<8) //查找下一个为0可放皇后的位置
j++;
EightQ(x+1,j++);//这里一定要要注意j++,否则返回后j不变,不进入上一步的while里加1,会导致死循环
copyArray(table,array_temp);//从下一层一个位置返回后,应对下一层的下一个位置进行求解,要恢复棋盘
// coutArray(table);
}
//cout<<countdg--<<endl;
return ;
}
求解得92个解