【算法百题之十七】八皇后的实现
大家好,我是Lampard~~
很高兴又能和大家见面了,接下来准备系列更新的是算法题,一日一练,早日升仙!
今天的问题是:
列举出8*8的棋盘上面存在着8个皇后的所有可能。首先我们简单提一下规则:
就是在同一行,同一列,同一斜线上不能出现两个皇后,不然的话女人打架就GG
那么我们可以借助二维数组代表棋盘来帮助我们递归实现这个功能:
关键的递归方法:
void EightQueen(int row, int (*chess)[8])
{
// 参数row表示第几行,参数*chess【8】表示棋盘行的指针,每行有8列
int chess2[8][8];
for (int i = 0; i < 8; i++)
{
// 定义chess2是为了不改变原来的棋盘,确保这个棋盘的row一下的列是干净的
for (int j = 0; j < 8; j++)
{
chess2[i][j] = chess[i][j];
}
}
if (row == 8)
{
cout << "第" << num <<"种符合条件的棋盘" << endl;
print(chess);
num++;
}
else
{
for (int j = 0; j < 8; j++)
{
if (NotDanger(row, j, chess))
{
for (int i = 0; i < 8; i++)
{
// 把棋盘里面第row行所有的元素全部赋值0
chess2[row][i] = 0;
}
chess2[row][j] = 1;
EightQueen(row + 1, chess2);
}
}
}
}
首先我们看看我们这个方法的参数,和这个方法想要实现的功能:
参数传入的是row代表第几行,
(*chess)[8]代表的是传入了一个二位数组,这个二维数组有8行,我们知道每一行有8列
这个函数的目的是在第row行这里,找到一个位置放置皇后。
我们知道,递归的函数肯定要有一个结束的标志
在这个函数里面就是当row==8时结束(行数索引的范围是0~7),当row等于8时就输出整个棋盘。
那么当row不等于8之前要怎么做呢?
很简单,我们不是要在这一行找到位置放皇后吗?
那么我们只需要循环每一列判断一下这个位置安不安全,安全就把这个位置放皇后,然后进行下一行的递归就OK了。
好,然后我们接着看一下判断函数
bool NotDanger(int row, int col, int(*chess)[8])
{
int flag=0;
int i, k;
for( i = 0 ; i< row ; i++)
{
// 判断列的方向有没有危险,col这一列有没有皇后的存在
if (chess[i][col] != 0)
{
flag = 1;
break;
}
}
for ( i = row, k = col; i >= 0 && k >= 0; i--, k--)
{
// 判断左上方
if (chess[i][k] != 0)
{
flag = 1;
break;
}
}
for ( i = row, k = col; i >= 0 && k<8; i--, k++)
{
// 判断右上方
if (chess[i][k] != 0)
{
flag = 1;
break;
}
}
if (flag != 0) {
return false;
}
else
return true;
}
这个函数的意义是判断第row行第col列安不安全。
判断方法没什么好说的,因为我们是一行一行的放皇后,所以同一行肯定是不会出现两个皇后的
然后是判断一下同一列有没有两个皇后,接着就是左上方和右上方判断一下斜着有没有出现皇后。
很普通,就像古天乐的样子一样平平无奇。
什么?你问我为什么不判断下方的斜线?
别忘了,我们是一行一行往下放皇后的,所以第row行下方此时是没有任何棋子。
最后是输出函数和测试函数
void print(int(*chess)[8])
{
// 输出棋盘
for (int i = 0; i < 8; i++)
{
for (int j = 0; j < 8; j++)
{
cout << chess[i][j] << " ";
}
cout <<endl;
}
}
int main()
{
// 初始化棋盘
int chess[8][8] = { 0 };
// 从第0行开始
EightQueen(0, chess);
}