LeetCode51.N皇后,面试题 08.12.八皇后 原题链接:N皇后 原题链接:八皇后

1. 需要了解的知识点

全排列模板(回溯)

dfs()
{
    if()    //出口
    {
        return ;
    }
    for(int i=0;i<n;i++)    //列举所有情况
    {
        if(!pd[i])
        {
            pd[i]=1;
            dfs();      
            pd[i]=0;        //回溯
        }
    }
}

相关视频链接:【算法】dfs刷题实战1

2. 难点:

皇后不能放置在对角线上

3. 思路

把这道题考虑成全排列问题,比如八个皇后在棋盘上放置的位置可以是
第一行第1个 | 第一行第1个 | 第一行第1个
第二行第2个 | 第二行第3个 | 第一行第4个
第三行第3个 | 第二行第2个 | 第一行第2个
、、、、、、  、、、、、    、、、、、
第八行第8个 | 第二行第8个 | 第一行第8个

考虑完了行列不同,接下来考虑对角线,如果两个皇后在一条对角线上,必定两个点的坐标满足  abs(行1-行2)==abs(列1-列2)

4. 代码注释

变量定义的解释

vector<vector<string>> vecvec:需要返回的目标字符串数组

vector<int> pd(n,-1):储存行号和列号,pd[0]下标0代表行号,pd[0]的值代表列号,不必定义二维数组,但一维数组理解可能麻烦一点。

int n:多少个皇后,棋盘的长宽

int count:当前的行号

class Solution {
public:
void dfs(int n, vector<int> pd,int count,vector<vector<string>>& vecvec)
{
    /*count为第多少行,pd[count]为第多少列*/

    if (count >= n)            /*出口*/
    {
         /*用于测试pd里面的值
         for (auto i : pd)
            cout << i << " "; cout<<endl;
        */
                               /*打印放入目标数组中*/
        vector<string> vec;
        for (auto i : pd)
        {
            string str;
            for (int j = 0; j < n; j++)
            {
                if (i != j)
                    str.push_back('.');
                else
                    str.push_back('Q');
            }
            vec.push_back(str);
        }
        vecvec.push_back(vec);
        return ;
    }
    for (int i = 0; i < n; i++)                  /*排列所有情况*/
    {    
        pd[count] = i;                           /*第count行将皇后放到第i列*/
        int bean = 1;                             /*标记是否可以放皇后,1可以放*/        
            for (int k = 0; k < count; k++)      /*之前放过的所有皇后的坐标,遍历会不会攻击当前皇后*/
            { 
                if ( pd[k] == pd[count])         /*属于同一列*/
                {                
                    bean = 0;                    /*标记为不能放*/
                }     
                if (abs(count-k) == abs(i-pd[k])) /* 行-行 == 列-列 */    
                    bean = 0;                     /*对角线(核心代码)*/
            }
            if (bean == 1)
            {    
                dfs(n, pd, count + 1, vecvec);      /*递归*/
            }
    }
}
vector<vector<string>> solveNQueens(int n) {
    vector<vector<string>> vecvec;
    vector<int> pd(n,-1);                        /*初始化*/
    
    /*递归深搜*/
    dfs(n, pd,0,vecvec);
    return vecvec;
}
};

4. 总结反思

此题没有回溯,之前在书上看的算法记得可以用一维数组搞定。过程中全程都在修改abs那行,测试可以去掉abs那行看,会发现全排列表现的很明显。

测试代码

int main()
{
    vector<vector<string>> vec;
    vec=solveNQueens(8);
    cout << "***" << vec.size() << endl;
    for (auto i : vec)
    {
        for (auto j : i)
        {
            for (auto k : j)
                cout << k << " ";
            cout << endl;
        }
        cout << endl;
    }
}

测试图片

图片名称