前言
N皇后问题是非常经典的回溯和剪枝的应用,也是数据结构与算法课程中非常重要的一个算法思想。它一般采用DFS也称深度优先搜索算法来解决。通过一道例题来具体介绍一下这类题目的解法和其算法思想。
一、题目描述
题目为 hdu2553 “N皇后问题”
在N*N的方格棋盘放置了N个皇后,使得它们不相互攻击(即任意2个皇后不允许处在同一排,同一列,也不允许处在与棋盘边框成45角的斜线上。 你的任务是,对于给定的N,求出有多少种合法的放置方法。
输入
共有若干行,每行一个正整数N≤10,表示棋盘和皇后的数量;如果N=0,表示结束。
输出
共有若干行,每行一个正整数,表示对应输入行的皇后的不同放置数量。
样例输入
1
8
5
0
样例输出
1
92
10
二、思路
以四皇后问题为例,从第一行开始放皇后,第1行从左到右有4种方案,产生4个子状态,从这4个子状态出发,又能展开6种相同深度的子状态,依次递归下去,直到把图填满。这里展开的过程虽然像是BFS,但实际上在DFS中,是将一种子状态一直向深遍历到结果或遇到错误情况,才会回退。
那么判断错误的条件是什么?
设已经放好的皇后坐标是(i ,j),当前要判断的坐标是(c,r)
- 行不相同,即i!=r
- 列不相同,即j!=c
- 还有斜对角线不相同,有(i-a,j-a),(i+a,j-a),(i-a,j+a),(i+a,j+a)四种情况,那么(i,j)点在各自移动a的距离后,产生了上述的四种条件下,我们其实可以把情况概括为c与i,和r与j点的距离不能是a,那么就是abs(i - r)!=abs(j - c)
其他的部分通过阅读代码就可以很好理解了
三、代码实现
#include<bits/stdc++.h>
using namespace std;
int col[15]={0};
int tot;
int n;
bool check(int c,int r) //该行用来检查是否与之前放好的皇后有冲突
{
for(int i=0;i<r;i++) //遍历当前行之前的情况
{
if(col[i]==c||abs(col[i]-c)==abs(i-r))
{
return false;
}
}
return true;
}
void dfs(int r) //一行一行地放皇后,这次是第r行
{
if(r==n) //遍历完所有的0~n-1的情况,进入到n层中,说明已经符合要求
{
tot++;
return;
}
for(int c=0;c<n;c++) //在每一列放皇后
{
if(check(c,r)) //check通过,可以在此处安放
{
col[r]=c; //将该行下的列号存入数组中
dfs(r+1); //进行下一层的遍历
}
}
}
int main()
{
int ans[12]={0};
for(n=0;n<=10;n++) //算出所有N皇后的答案,先打表,不然会超时
{
memset(col,0,sizeof(col)); //清空,准备计算下一个值为N的皇后问题
tot=0;
dfs(0);
ans[n]=tot; //打表
}
while(cin>>n)
{
if(n==0)
return 0;
cout<<ans[n]<<endl;
}
return 0;
}