求解N皇后问题是算法中回溯法应用的一个经典案例,回溯算法也叫试探法,它是一种系统地搜索问题的解的方法。回溯算法的基本思想是:从一条路往前走,能进则进,不能进则退回来,换一条路再试。(参:http://blog.csdn.net/hackbuteer1/article/details/6657109,http://www.cnblogs.com/yanlingyin/archive/2011/12/19/2292041.html)
把棋盘存储为一个N维数组a[N],数组中第i个元素的值代表第i行的皇后位置,这样便可以把问题的空间规模压缩为一维O(N),在判断是否冲突时也很简单,首先每行只有一个皇后,且在数组中只占据一个元素的位置,行冲突就不存在了,其次是列冲突,判断一下是否有a[i]与当前要放置皇后的列j相等即可。至于斜线冲突,通过观察可以发现所有在斜线上冲突的皇后的位置都有规律即它们所在的行列互减的绝对值相等,即| row – i | = | col – a[i] | 。这样某个位置是否可以放置皇后的问题已经解决。
下面是用递归的方式解决N皇后问题:
#include <iostream>
#include <cmath>
using namespace std;
const int n = 8;//皇后的个数
int a[n];//棋盘个数,n为皇后的行标,a[n]对应的值为皇后的列标
int number = 0;//一共有多少方案
void queen(int row);//递归放置皇后
void printQueen();//打印皇后方案
bool can_place(int row);//判断是否放置皇后
void main()
{
queen(0);//从第一行开始查找皇后
}
void queen(int row)
{
if (n == row)
{
printQueen();
}
else
{
for (int j = 0; j < n; ++j)
{
a[row] = j;
if (can_place(row))//第row行插入皇后成功者进入下一行,否则转到该行的下一列即++j
{
queen(row + 1);
}
}
}
}
void printQueen()
{
++number;
for (int i = 0; i < n; ++i)
{
cout << a[i] << ":";
}
cout << "\n-------" << number << "------" << endl;
}
bool can_place(int row)
{
for (int i = 0; i < row; ++i)
{
if (a[row] == a[i]/*查看第a[row]列是否有皇后*/ || abs(row - i) == abs(a[row] - a[i])/*查看对角线上是否有皇后*/)
{
return 0;
}
}
return 1;
}
下面是用非递归的方式解决N皇后问题:
#include <iostream>
using namespace std;
void Queen();
bool CanPlace(int * a, int row);//能否放置皇后
void printQueen(int * a, int n);
const int n = 8;//n个皇后
int queens[n] = { -1 };//列数初始化为-1
int sum = 0;//皇后放置方案总数
void main()
{
Queen();
}
void Queen()
{
int row = 0;
while (row>=0)
{
++queens[row];//判断该列是否可以放置皇后
//int m = 0;
while (queens[row]<n && !CanPlace(queens, row))//不能放置皇后则移动到下一列,否则跳出循环
{
queens[row] += 1;
}
if (queens[row]<n)//在上述while条件中找到能放置皇后的列位置后,可以换行,对row加1
{
if (row==n-1)//最后一行时,输出该放置皇后方案
{
printQueen(queens,n);
}
else //不是最后一列则换到下一行,并从第0列开始判断
{
++row;
queens[row] = -1;//设置为-1是为了每行开始从0列开始查找皇后位置
}
}
else //如果该行找不到可以防止皇后位置,则退回上一行继续寻找(回溯)
{
--row;
}
}
}
bool CanPlace(int * a ,int row )//能否放置皇后
{
for (int i = 0; i < row; ++i)
{
if (a[row] == a[i]/*查看第a[row]列是否有皇后*/ || abs(row - i) == abs(a[row] - a[i])/*查看对角线上是否有皇后*/)
{
return 0;
}
}
return 1;
}
void printQueen(int * a,int n)
{
++sum;
for (int i = 0; i < n; ++i)
{
cout << a[i] << ":";
}
cout << "\n-------" << sum << "------" << endl;//输出方案数
}