n(2n)皇后问题

n皇后问题:

思想:DFS深度遍历。

大体过程是:从网络的每一行开始遍历,首先从第一行开始。在每一行遍历该行所在的列,每一列依次检查,如果当前列满足条件(也就是不重列,不重对角线,这里的行重复这个条件不用管,因为我们每一行只放一个),那么就说明这一行可以放,就可以转入到下一行中了,下一行的操作思想同这一行一样,所以这就是一个递归过程。要注意的是,当成功全部放置完成时,也就是n行全部摆满,这时候就可以将技术方法+1了。另外,DFS当前递归完成时,会进行回退操作,我们就开始尝试当前列的下一列,所以我们要将之前放置的皇后给回收,也就是a[N]置0。

#include
#include
#include

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
#include
#include
#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;
}

你可能感兴趣的:(C,深度优先,算法,蓝桥杯)