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 位运算记录
位运算太渣。看不懂啊。。。。