leetcode 51. N 皇后 思考分析

118 阅读2分钟

目录

题目

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

思考

首先以N=4为例,画出解空间树的一部分:
在这里插入图片描述

根据模板:

void backtracking(参数)
{
	if(终止条件)
	{
		存放结果;
		return;
	}
	for(选择:本层集合中元素(树中结点孩子的数量就是集合的大小))
	{
		处理结点;
		backtracking(路径,选择列表);		//递归
		回溯,撤销处理结果;
	}
}

1、确定回溯函数参数,返回值
当前所在的行(层),当前的棋盘布局。
N的大小

void backtracking(int hang,vector<string>& chessboard,int n)

全局变量:vector<vector>result;
result是个存放chessboard的变量。
这里的chessboard就相当于之前回溯题目中的path、子结果。
2、确定终止条件:
当遍历到N的最后一层(n-1)时,再往下一层,我们就需要返回了。

if(hang == n)
{
	result.push_back(chessboard);
	return ;
}

3、确定单层逻辑
如果本行的某列放入皇后,且不违反规则,即可进入下一行探索

 for(int lie = 0;lie < n ;lie++)
{
     if(juge_if_valid(hang,lie,chessboard,n) == true)
     {
         chessboard[hang][lie] = 'Q';	//放置皇后
         backtracking(hang+1,chessboard,n);
         chessboard[hang][lie] = '.';	//回溯撤销
     }
 }

4、判断是否满足分布条件有三个:

1、皇后不在同一行
2、皇后不在同一列
3、皇后不在同一斜线上

a、同时我们注意,我们探索的时候就是按照深度探索的,所以保证了每一行只有一次赋值Q。所以第一个条件不需要特别处理。
b、由于按照深度往下搜索,所以判断皇后在同一列的时候可以剪枝:

//检查本行之上的行的同一列是否存在Q
for(int i=0;i<hang;i++)
{
	if(chessboard[i][lie] == 'Q') return false;
}

c、由于按照深度往下探索,所以判断皇后在同一斜线的时候可以剪枝(注意,斜线分为向右上斜和左上斜两个方向)

//检查本行之上的行的右斜线上是否有皇后
for(int i=hang-1,j=lie-1;i>=0 && j>=0;i--,j--)
{
	if(chessboard[i][j] == 'Q') return false;
}
//检查本行之上的行的左斜线上是否有皇后
for(int i=hang-1,j=lie+1;i>=0 && j<n;i--,j++)
{
	if(chessboard[i][j] == 'Q') return false;
}

AC代码

class Solution {
public:
    vector<vector<string>>result;
    bool juge_if_valid(int hang,int lie,vector<string>&chessboard,int n)
    {
        //检查本行之上的行的同一列是否存在Q
        for(int i=0;i<hang;i++)
        {
            if(chessboard[i][lie] == 'Q') return false;
        }
        //检查本行之上的行的右斜线上是否有皇后
        for(int i=hang-1,j=lie-1;i>=0 && j>=0;i--,j--)
        {
            if(chessboard[i][j] == 'Q') return false;
        }
        //检查本行之上的行的左斜线上是否有皇后
        for(int i=hang-1,j=lie+1;i>=0 && j<n;i--,j++)
        {
            if(chessboard[i][j] == 'Q') return false;
        }
        return true;
    } 
    void backtracking(int hang,vector<string>& chessboard,int n)
    {
        if(hang == n)
        {
            result.push_back(chessboard);
            return ;
        }
        for(int lie = 0;lie < n ;lie++)
        {
            if(juge_if_valid(hang,lie,chessboard,n) == true)
            {
                chessboard[hang][lie] = 'Q';	//放置皇后
                backtracking(hang+1,chessboard,n);
                chessboard[hang][lie] = '.';	//回溯撤销
            }
        }
        return ;
    }
    vector<vector<string>> solveNQueens(int n) {
        result.clear();
        //填充初始棋盘
        vector<string> chessboard(n,string(n,'.'));
        backtracking(0,chessboard,n);
        return result;
    }
};