回溯法刷题整理(N皇后)

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

在这里插入图片描述

上图为 8 皇后问题的一种解法。

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

每一种解法包含一个明确的 n 皇后问题的棋子放置方案,该方案中 ‘Q’ 和 ‘.’ 分别代表了皇后和空位。

示例:

输入: 4
输出: [
[".Q…", // 解法 1
“…Q”,
“Q…”,
“…Q.”],

["…Q.", // 解法 2
“Q…”,
“…Q”,
“.Q…”]
]
解释: 4 皇后问题存在两个不同的解法。

在这里插入图片描述
首先,比如在1a处放置一个皇后,则a列和1行以及斜线都不能放置皇后在这里插入图片描述
这里使用mark二维数组来标记已访问的点,标记为1
要实现这个功能,不如创建一个方法push_down_queen(),
参数传入放置的皇后的坐标,和mark数组
因为有八个方位,上下左右,左上,左下,右上,右下
这里用两个数组来实现(dx[],dy[])

private:
void push_down_the_queen(int x, int y, vector<vector<int>>& mark) {//放置皇后及其攻击范围的数组
		static const int  dx[] = { -1,1,0,0,-1,-1,1,1 };//移动坐标数组
		static const int  dy[] = { 0,0,-1,1,-1,1,-1,1 };
		mark[x][y] = 1;//标记当前放置皇后的位置为一
		for (int i = 1; i < mark.size(); i++) {//标记攻击范围为一,因为数组中的"0"位置已经放置了皇后,且已置零
			for (int j = 0; j < 8; j++) {//八个方向
				int new_x = x + i*dx[j];//往上置零,则坐标一直往上移动(用i*dx[j]实现)
				int new_y = y + i*dy[j];
				if (new_x >= 0 && new_x < mark.size() && new_y >= 0 && new_y < mark.size()) {
					mark[new_x][new_y] = 1;
				}
			}
		}
	}

一次内循环置一次"1"
黑色的"1"对应i=1时
绿色的"1"对应i=2时
红色的"1"对应i=3时
因为有八个方位,所以内循环8次
在这里插入图片描述
1-1.假如在1a放置了皇后,则按照顺序只能在2c放置皇后,如此任由它进行下去,有可能会出现放置的皇后数 ! = n 的情况,这时候就需要回溯了
在这里插入图片描述

public:
	vector<vector<string>> solveNQueens(int n) {
		vector<vector<int>> mark;//标记数组,指定不能放置的位置
		vector<string> location;//存储某个摆放结果
		vector<vector<string>> result;
		for (int i = 0; i < n; i++) {
			mark.push_back((vector<int>()));//为后续二级数组push做前提,否则无法访问二级数组
			for (int j = 0; j < n; j++) {
				mark[i].push_back(0);
			}
			location.push_back("");
			location[i].append(n, '.');//初始化
		}
		generate(0, n, mark, result, location);
		return result;

	}

location数组作为当前情况的记录数组,result数组作为最终满足放置的皇后数==n的结果数组,
先初始化矩阵,然后进入递归generate()

private://k为当前的皇后标号,n皇后,mark标记数组,result结果数组,location用于存储当前放置的皇后的数组
	void generate(int k, int n, vector<vector<int>>& mark, vector<vector<string>>& result, vector<string>& location) {
		if (k == n) {
			result.push_back(location);//当符合条件时,放入结果数组中
			return;
		}
		for (int i = 0; i < n; i++) {//按顺序尝试1至n列
			if (mark[k][i] == 0) {
				vector<vector<int>> temp_mark = mark;//镜像数组,便于回溯
				location[k][i] ='Q';//放置当前皇后
				push_down_the_queen(k, i, mark);//更新标记数组
				//vector<string> 数组可以像location一样操作,即用单引号,可以类似二维数组操作
				generate(k + 1, n, mark, result, location);//递归
				mark = temp_mark;//回溯
				location[k][i] = '.';
			}
		}
	}

递归的结束条件即放置的皇后数== n的情况,按照1-1的算法思想,需要按列的顺序试着放入皇后,这时候就要用到mark标记数组作为准入条件,先建立一个镜像mark,而后放置皇后,再进入递归,回溯的话就要用到刚刚的镜像数组mark了。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值