N皇后问题的深度解析(前提是会递归和dfs)

;52. N皇后 II](https://leetcode-cn.com/problems/n-queens-ii/)

n 皇后问题 研究的是如何将 n 个皇后放置在 n×n 的棋盘上,并且使皇后彼此之间不能相互攻击。

给你一个整数 n ,返回 n 皇后问题 不同的解决方案的数量。

示例 1:

img

输入:n = 4
输出:2
解释:如上图所示,4 皇后问题存在两个不同的解法。

示例 2:

输入:n = 1
输出:1

提示:

  • 1 <= n <= 9
  • 皇后彼此不能相互攻击,也就是说:任何两个皇后都不能处于同一条横行、纵行或斜线上。

其实这道题,我一开始是不大想做的,毕竟image-20210226070852309,毕竟上面写着困难,但是!但是通过率高达80%;而且通过人数image-20210226070944428所以我就下定决心做一做了;

这种题一看就是递归,更像是搜索;而且是深度搜索(DFS);

但是如何满足以下:

任何两个皇后都不能处于同一条横行、纵行或斜线上

其实大可以设置一个数组,如果在判断之后在这一个点上可以放置皇后,那么将数组中这一点的横竖斜纵都设置为1;

但是这样写比较麻烦(我一开始就是这样写的);

那么我们大可以找一找规律:

只要这一行有一个皇后,那么这一行就不能用(可以设置一个flag数组,当这一行有了,就标志为1,如果没有就标志为0);

只要这一列有一个皇后,那么这一列就不能用(同样可以设置一个数组);

只要这"\"左斜线有一个皇后,那么经过思索你就会发现,这一条斜线上(x-y)上的值是一样的[你可以将这一个棋盘想象成一个坐标系,将这一条斜线想象成一个方程,而这个方程中(x-y)的值的的确确不会变化,就是一个常数值];

那么右斜线呢?右斜线中(x+y)的值是不会变的(如上);

!image-20210226072959101


以上就是规律,那么看以下代码

#include "head.h"//此处不重要,是我储存头文件的地方;

class Solution
{
public:
	vector<int> rows;
	vector<int> cols;
	vector<int> left;
	vector<int> right;
	int cnt;
	int array[9][9];//此处用不到;
	int totalNQueens(int n)
	{
		//cout << 1 << endl;
		//对横竖斜纵进行初始化;
		rows.resize(10, 0);
		cols.resize(10, 0);
		left.resize(20,0);//如果好奇为什么以上都是10,而下面都是20可以看看以下代码;
		right.resize(20, 0);
		cnt = 0;
		//cout << 1<<endl;
		memset(array, 0, sizeof array);//对数组初始化,但是下面用不到;
		//int k = 1;	cout << 11 << endl;
		find(1, n);//开始dfs,其实如果n为类成员变量的话,同样可以将n去掉;

		return cnt;
	}
	void find(int x, int all)
	{
		if (x == all + 1)//边界条件,main函数中假设的是5,所以当x成了6的时候,说明前面都已经前五行都已经排满了,所以才会到达这个地步;
		{
			cnt++;
			return;
		}
		int i;
		for (i = 1; i <= all; i++)//对某一行的每一个点都要判断
		{

			if (judge(x, i))//judge用来判断是否可以放入皇后这一个位置;
			{
			//以下是回溯;---->我所了解的回溯就是以下这种套路,不会没关系,我递归都学了好几个月才差不多会用它做题;
				set_all(x, i);//进入到这里说明可以放入,那么就标志起来,
				find(x + 1, all);
				can_all(x, i);//取消
			}
		}
	}

	void set_all(int x, int y)//如果(x,y)要放置皇后,那么就将这一个点的横纵斜竖全部标志为1;
	{
		rows[x] = 1;
		cols[y] = 1;
		left[x - y + 9] = 1;//这里是重点,在上面讲述技巧的时候,你会发现,如果要设置标志数组的话,(x-y)的值有可能是负数,那么避免的方法就是+n,让x-y无论如何都是正数;
		right[x + y] = 1;//而此处的话,之所以要将数组设置成20,是因为(x+y)的值有可能会超过十;
	}
	void can_all(int x, int y)//取消;
	{
		rows[x] = 0;
		cols[y] = 0;
		left[x - y + 9] = 0;
		right[x + y] = 0;
	}
	bool judge(int x, int y)
	{
		if (rows[x] == 1)
			return false;
		if (cols[y] == 1)
			return false;
		if (left[x - y + 9] == 1)
			return false;
		if (right[x + y] == 1)
			return false;
		return true;
	}
};
int main()
{
	Solution x;
	//cout << 10 << endl;
	cout << x.totalNQueens(5);
}

怎么说呢,一开始觉得这种题不适合我做,但是做出来之后异常的兴奋,毕竟上面标志的难题我做了出来(尽管!尽管做了n个小时).为了以后能找到不错的工作,我拼了!

/cout << 10 << endl;
cout << x.totalNQueens(5);
}


怎么说呢,一开始觉得这种题不适合我做,但是做出来之后异常的兴奋,毕竟上面标志的难题我做了出来(尽管!尽管做了n个小时).为了以后能找到不错的工作,我拼了!


猜你喜欢

转载自blog.csdn.net/weixin_45929885/article/details/114110119