n皇后问题:
思想:DFS深度遍历。
大体过程是:从网络的每一行开始遍历,首先从第一行开始。在每一行遍历该行所在的列,每一列依次检查,如果当前列满足条件(也就是不重列,不重对角线,这里的行重复这个条件不用管,因为我们每一行只放一个),那么就说明这一行可以放,就可以转入到下一行中了,下一行的操作思想同这一行一样,所以这就是一个递归过程。要注意的是,当成功全部放置完成时,也就是n行全部摆满,这时候就可以将技术方法+1了。另外,DFS当前递归完成时,会进行回退操作,我们就开始尝试当前列的下一列,所以我们要将之前放置的皇后给回收,也就是a[N]置0。
#include<iostream>
#include<cstdlib>
#include<cstdlib>
using namespace std;
const int N = 10;
int n;
int a[N];//a[i]表示第i行上的皇后放于a[i]列上,假设a[3]=7,也就是第三行的皇后放于第七列的单元格上
int cnt;
bool check(int x, int y) {//第x行,能不能把皇后放在y上面
for (int i = 1; i <= x; i++) {
if (a[i] == y) return false;
if (i + a[i] == x + y) return false;
if (i - a[i] == x - y) return false;
}
}
void dfs(int row) { //第几行皇后放于何处
if (row == n + 1) {
cnt++;//产生了一组这样的解
return;
}
for (int i = 1; i <= n; i++) {
if (check(row, i)) {
a[row] = i;
dfs(row + 1);//如果能放就继续下一行
a[row] = 0;
}
}
}
int main() {
cin >> n;
dfs(1);
cout << cnt;
return 0;
}
2n皇后问题
2n皇后问题总体看来跟n皇后问题差不多。
具体思路:先放置黑皇后,检查当前皇后能不能放入当前位置(棋盘允许放入吗),如果允许,就将棋子放入,然后进行进一步检查(列不重复,对角线不重复,行因为是我们每行只放一个,所以这个不用判断),如果满足条件,剩下的道理就同n皇后一样了,开始处理下一行,另外这里也要注意在当前列结束进入下一列时,记得回收当前放置的棋子,以及递归结束条件是所有行全部放完,也就是放到了n+1行。到了n+1行表示黑棋子已放完,然后我们接着放白棋子。道理同黑棋子一样,具体细节看注释就ok。
#include<iostream>
#include<stdio.h>
#include<stdlib.h>
#define N 10
using namespace std;
int n;
int checkerboard[N][N];
int posb[N];
int posw[N];
int total = 0;
bool checkw(int current_row) //检查函数
{
for (int i = 1; i < current_row; i++)
if (posw[i] == posw[current_row] || abs(i - current_row) == abs(posw[i] - posw[current_row]))
return false;
return true;
}
bool checkb(int current_row) //检查函数
{
for (int i = 1; i < current_row; i++)//行遍历
if (posb[i] == posb[current_row] || abs(i - current_row) == abs(posb[i] - posb[current_row]))
return false;
return true;
}
void dfs_white(int current_row)
{
if (current_row == n + 1) //白皇后也全部放完,次数+1
{
total++;
}
for (int i = 1; i <= n; i++)
{
if (posb[current_row] == i) //表示第current_row行的第i列位置已经被黑皇后占用,
continue; //结束当前循环,i+1
if (checkerboard[current_row][i] == 0) //再判断前提条件是否成立
continue;
posw[current_row] = i; //尝试把第current_row行的白皇后放在第i列上
if (checkw(current_row)) //判断能否放置白皇后
dfs_white(current_row + 1); //递归
else
posw[current_row] = 0;
}
}
void dfs_black(int current_row)//当前第一行
{
if (current_row == n + 1) //当黑皇后处理完时,再处理白皇后
{
dfs_white(1);
}
for (int i = 1; i <= n; i++)//列遍历
{
if (checkerboard[current_row][i] == 0) //如果第current_row行第i列满足放皇后的前提条件即 checkerboard[current_row][i] == 1
continue; //如果不满足,则结束当前循环,进行下一次循环即i+1。
posb[current_row] = i; //就尝试把第current_row行的黑皇后放在第i列上
if (checkb(current_row)) //然后判断该尝试是否成立,如成立,则进行递归,如不成立,则尝试把当前列的黑皇后放在下一行(i+1行)上。
dfs_black(current_row + 1); //递归
posb[current_row] = 0;
}
}
int main() {
cin >> n;
for (int i = 1; i <= n; i++) //定义棋盘
for (int j = 1; j <= n; j++)
cin >> checkerboard[i][j];
dfs_black(1); //先摆黑皇后
cout << total << endl;
return 0;
}