首先介绍一下八皇后的问题。这是一个古老而著名的问题,指的是在一个8X8的国际象棋棋盘上,有八个皇后,每个皇后占一个;要求皇后之间不会出现相互攻击的现象,即不能有两个皇后处在同一行、同一列或同一对角线上。问一个有多少种不同的排列方法?
下面是代码:
#include<iostream>
using namespace std;
static int gEightQueen[8] = { 0 }, gCount = 0;
void print()//输出每一种情况下棋盘中皇后的摆放情况
{
for (int i = 0; i < 8; i++)
{
int inner;
for (inner = 0; inner < gEightQueen[i]; inner++)
cout << " ";
for (inner = gEightQueen[i] + 1; inner < 8; inner++)
cout << "";
cout <<"#" << endl;
}
cout << "==========================\n";
}
int check_pos_valid(int loop, int value)//检查是否存在有多个皇后在同一行/列/对角线的情况
{
int index;
int data;
for (index = 0; index < loop; index++)
{
data = gEightQueen[index];
if (value == data)
return 0;
if ((index + data) == (loop + value))
return 0;
if ((index - data) == (loop - value))
return 0;
}
return 1;
}
void eight_queen(int row)
{
int loop;
for (loop = 0; loop < 8; loop++)
{
if (check_pos_valid(row,loop))
{
gEightQueen[row] = loop;
if (7 == row)
{
gCount++, print();
gEightQueen[row] = 0;
return;
}
eight_queen(row + 1);
gEightQueen[row] = 0;
}
}
}
int main(int argc, char*argv[])
{
eight_queen(0);
cout << "total=" << gCount << endl;
return 0;
}
鉴于这个算法稍微有那么点复杂,我就来分析一下这个算法的实现过程。首先这个算法用的是回溯法,它是一种搜索问题的解方法,有关更具体的回溯法的思想,我就不废话了,有新的同学去google吧!下面开始讲解:
首先说明一下eight_queue函数是测试row行皇后的位置,然后再调用check_pos_valid函数测试这个位置是不是满足题意,check_pos_valid函数的参数第一个是当下这个皇后的行坐标,第二个参数是纵坐标,然后和以前的皇后一一对比,当再同一列和同一行的情况就是:
if (value == data)
return 0;
当位于对角线时的情况是下面的两种:
if ((index + data) == (row + value))
return 0;
if ((index - data) == (row - value))
return 0;
你们可以再纸上自己画一下看看是不是这个规律分别是:当在最上角到右下角的对角线上时规律是行号减去行号等于列号减去列号,当是右上角到左下角的对角线上时,本身的行号和列号相加等于对角线上另一个元素的行号加上列号。好了,这个函数分析完毕,然后我们分析eight_queue函数,这个是重点,也是不好理解的地方。
首先对于第一行的皇后的位置置为0(eEightQueue[row]=i表示皇后再第row行的第i列),然后进入上面的函数,判断是否符合规范,是的话,row+1,进行下一行位置的选定和判断,别忘了这是用的递归。重点来了,当row到达最后一行时,这是row=7,然后总方法变量+1,让row=7的皇后位置设为0,进行return回退,回到前一行,并且也将前一行的位置设为0.这便是回退的思想,就是这样,一步一步回退,一直回到最初的第一行,这边是把整个情况全部遍历了一遍,得到了总方法。其中if语句的内容是非常重要的,要多看即便你们。虽然这种方法简单好用,但是对于小数据还行,当数据很大时,变会产生很大的时间复杂度。最后要想升级快,每天多打怪!!!