1 八皇后
八皇后的问题是:
一个8X8的棋盘上,摆上8个皇后,皇后的攻击方式是,斜着,横着,竖着。要求摆的8个皇后不能够相互攻击到。
2 分析
八皇后的解法是回溯算法。
而关键问题就在于:判断某个点是否可以摆。
3 解法
3.1 使用二维数组备忘
使用二维数组做备忘,直观很多。按部就班的判断是否可以防止就行了。
#include <vector>
#include <iostream>
using namespace std;
bool aux_judge(int row, int col, vector<vector<int>> &memo)
{
// 只用到row 的原因在于,后面的都没摆,因此可以不用判断
// 判断同一列
for (int i = 0; i < row; ++i)
{
if (memo[i][col] == 1)
{
return false;
}
}
// 判断右斜,因此是row和col都要减少相同的
for (int i = 1; col - i >= 0 && row - i >= 0 ; ++i)
{
if (memo[row - i][col - i] == 1)
{
return false;
}
}
// 判断左斜,因此row是在减,col是在加
for(int i=1;col+i<8&&row-i>=0;++i)
{
if(memo[row-i][col+i]==1)
{
return false;
}
}
return true;
}
// row 开始摆第row-1行,ret为解的个数
void aux(int row, vector<vector<int>> &memo, int &ret)
{
// 当row==8 的时候,也就是说前面0~7行,这8行都摆了,那么已经完成了一个解
if (row == 8)
{
ret++;
return;
}
// 这一行的 8 个位置依次试一下
for (int i = 0; i < 8; ++i)
{
// 判断 row,i 这个点是否可以摆
if (aux_judge(row, i, memo))
{
memo[row][i] = 1;
aux(row + 1, memo, ret);
memo[row][i] = 0; // 回溯
}
}
}
int eight()
{
// 使用一个二维数组,记录已经摆的点。可以用bool的。
vector<vector<int>> memo(8, vector<int>(8, 0));
int ret = 0;
aux(0, memo, ret);
return ret;
}
3.2 使用一位数组备忘
使用一个8长度的一维数组备忘,数组的低i位,表示第i行,皇后放在arr[i]位置上。
其中判断是否可以方式的时候,是初中数学时候的知识,也就是 x+y=c1,和y-x=c2.
bool aux_check(int row, int col, vector<int> &memo)
{
for (int i = 0; i < row; ++i)
{
// 判断是否有皇后在
if (memo[i] == col)
{
return false;
}
// memo[i] + i == row + col 的含义是:
// 当2个点的横纵坐标相加和相等的时候,就类似于 x+y =n ,那么两点在同一纸箱上
// 同理 memo[i] -i== col -row 表示
// 当两个点的横纵坐标差相等时,类似于 x-y =c ,那么两点也在同一直线上。
if (memo[i] + i == row + col || memo[i] -i== col -row)
{
return false;
}
}
return true;
}
void aux(int row, vector<int> &memo, int &ret)
{
if (row == 8)
{
ret++;
return;
}
for (int i = 0; i < 8; ++i)
{
if (aux_check(row, i, memo))
{
memo[row] = i;
aux(row + 1, memo, ret);
// memo[row] = 0; // 这句话是可以省略的,
// 原因在于,在 aux_check() 判断的时候并不会用到这一行。
}
}
}
int eight()
{
// memo 记录的是第 i 行上的皇后位于 memo[i]列
vector<int> memo(8);
int ret = 0;
aux(0, memo, ret);
return ret;
}
3.2 位运算记录
位运算太渣。看不懂啊。。。。