八皇后的问题非常有名,初次理解可能稍有难度,不过多看书,看博客和代码,几遍下来,也基本清晰。
首先不用想初始的情况,先假设前面已经排列好了几个皇后,即将排列下一个皇后。依次遍历八个位置,然后与之前的进行判断这个位置是否可行,如可行则进行下一个皇后,否则则移动位置继续判断。很简单。但是有两个个问题:
1、不全,某个位置有八种方法排列,你只用了一种,当然你可以每个位置遍历,但太耗时,回溯法可以解决很大的一部分问题,即当你在对某一行皇后进行放置时,如果一直放不好(到最后),那后面的行就不需要再遍历了,直接回溯上一行,将上一行的位置后移——依次进行这个步骤,直到第一行,遍历结束。
2、如何判定当前位置合法?首先,两个皇后不能同一列(这里要注意,算法的遍历次序是按行来的,所以不必考虑行的情况),其次,不能斜对角。
代码如下,很清晰:
#define N 8
/* Place(),第一个参数表示八皇后的列位置,第二个表示当前要插入的八皇后的行数。 */
bool Place(int eightqueen[],int k)
{
int i = 0;
while(i<k)
{
if(eightqueen[i] == eightqueen[k] || abs(eightqueen[i] - eightqueen[k]) == abs(i- k))
{
return false;
}
i++;
}
return true;
}
行是从0开始,而列是从1开始。
1、递归解法
int eight_queen[N] = {0};
int gcount = 0;
void Eight_Queen_Recursion(int eight_queen[],int i)
{
eight_queen[i]++;
while(!Place(eight_queen,i) && eight_queen[i]<=N)
{
eight_queen[i] ++;
}
if(eight_queen[i] <= N)
{
if(i == N -1 )
{
gcount ++;
}
else
{
i++;
eight_queen[i] = 0;
}
Eight_Queen_Recursion(eight_queen,i);
}
else
{
i--;
if(i<0)
{
return;
}
Eight_Queen_Recursion(eight_queen,i);
}
}
void main()
{
Eight_Queen_Recursion(eight_queen,0);
cout<<gcount<<endl;
}
2、非递归解法
void Eight_Queen()
{
int eight_queen[N] = {0}; //初始化八皇后的列。每一行的八皇后所在的列
int i = 0;
int count = 0;
while(i>=0)
{
eight_queen[i]++; //从1开始
while(!Place(eight_queen,i) && eight_queen[i] <= N) //判断此列是否符合条件。
{
eight_queen[i] ++; //将列位置后移
}
if(eight_queen[i] <= N)
{
//找到一个位置
if(i == N-1)
{
//这是一个解
count ++;
}
else
{
//没有到最后一行,则进行下一行
i++;
eight_queen[i] = 0; //下一列从0开始
}
}
else//如果这一行到最后也没有找到合适的列,则回溯上一行。
{
i--;
}
}
cout<<count<<endl;
}
void main()
{
Eight_Queen();
}
将Place函数与下面的结合,即是完整的程序。