【回溯算法篇】N皇后问题

这篇具有很好参考价值的文章主要介绍了【回溯算法篇】N皇后问题。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

🌠作者:@阿亮joy.
🎆专栏:《数据结构与算法要啸着学》
🎇座右铭:每个优秀的人都有一段沉默的时光,那段时光是付出了很多努力却得不到结果的日子,我们把它叫做扎根
回溯法求n皇后问题,数据结构与算法要啸着学,算法,数据结构,c++,N皇后问题


👉N皇后II👈

n 皇后问题研究的是如何将 n 个皇后放置在 n × n 的棋盘上,并且使皇后彼此之间不能相互攻击。注:共行、共列或者共斜线的皇后都会相互攻击。

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

回溯法求n皇后问题,数据结构与算法要啸着学,算法,数据结构,c++,N皇后问题

皇后摆放的位置是否同行或者同列是很好判断的,关键是如何判断任意两个皇后是否共斜线。

回溯法求n皇后问题,数据结构与算法要啸着学,算法,数据结构,c++,N皇后问题

皇后放在不同行,这个是很容易就能够保证的。那么我们就需要保证皇后放在不同行且不共斜线。那么放入皇后的过程就是一个搜索的过程,搜索皇后之间不会相互攻击的位置。那我们需要将已经放入的皇后的所在位置,保存皇后的位置只需要一个整型数组record就行了,record[i] 的值表示第 i 行的皇后放在了第几列。

class Solution 
{
private:
    int total = 0;  // tatol为N皇后的摆法

    bool isValid(const vector<int>& record, int row, int col)
    {
        // 第i行的皇后
        // 判断是否和0行到row-1行的皇后共行、共列或者共斜线
        // 如果是,返回false;如果不是,返回true
        // 条件col == record[i]表示当前row行和i行的皇后共列
        // 两个皇后共斜线时,行标差的绝对值等于列标差的绝对值
        // 条件abs(record[i] - col) == abs(row - i)表示两个皇后共斜线
        for(int i = 0; i < row; ++i)
        {
            if(col == record[i] || abs(record[i] - col) == abs(row - i))
                return false;
        }
        return true;
    }

    void BackTracking(int row, vector<int>& record, int n)
    {
        // 当row等于n时,表示找到了一种摆法
        if(row == n)
        {
            ++total;
            return;
        }
        
        // 当前在第row行,需要遍历当前行的所有列看是否能放入皇后
        for(int col = 0; col < n; ++col)
        {
            // isValid函数是检查第row行的皇后放在第col列,会不会
            // 和之前0到row-1行的皇后共行、共列或者共斜线
            // 如果是,认为第row的皇后不能放在第col列,继续判断后面的列能不能放皇后
            // 如果不是,认为第row的皇后能放在第col列,递归去放第row+1行的皇后
            if(isValid(record, row, col))
            {
                // record[row]表示第row行的皇后放在了第col列
                record[row] = col;  
                BackTracking(row + 1, record, n);
            }
        }
    }

public:
    int totalNQueens(int n) 
    {
    	total = 0; // 防止同一个对象调用多次调用该函数
        vector<int> record(n);
        BackTracking(0, record, n);
        return total;
    }
};

回溯法求n皇后问题,数据结构与算法要啸着学,算法,数据结构,c++,N皇后问题

N 皇后的时间复杂度为 O(N^N)。

上面的解法还是可以进行优化,就是通过位信息来表示皇后的位置。这种优化是比较抽象的,但确实可以提高效率。

以八皇后问题为例,来了解通过位信息来判断皇后之间是否会相互攻击。

回溯法求n皇后问题,数据结构与算法要啸着学,算法,数据结构,c++,N皇后问题

class Solution 
{
private:
    // colLim 列的限制,1的位置不能放皇后,0的位置可以放皇后
    // leftDiaLim 左斜线的限制,1的位置不能放皇后,0的位置可以放皇后
    // rightDiaLim 右斜线的限制,1的位置不能放皇后,0的位置可以放皇后
    int BackTracking(int limit, int colLim, int leftDiaLim, int rightDiaLim)
    {
        // limit的低n位比特位全为1,如果colLim等于limit,
        // 也就说明n个皇后已经摆放好了,且不会相互攻击
        if (colLim == limit)
        {
            return 1;
        }

        // colLim | leftDiaLim | rightDiaLim为总限制,1表示不可以放皇后,0表示可以放皇后
        // ~(colLim | leftDiaLim | rightDiaLim):1表示可以放皇后,0表示不可以放皇后
        // pos中的低n位比特位:1表示该位置可以放皇后,0表示该位置不可以放皇后
        int pos = limit & (~(colLim | leftDiaLim | rightDiaLim));
        int mostRightOne = 0;
        int ret = 0;
        while (pos != 0)
        {
            // pos & (~pos + 1)可以将pos最右侧的1提取出来
            mostRightOne = pos & (~pos + 1);
            pos = pos - mostRightOne;   // 减去最右侧的1,尝试在次右侧的1的位置上放皇后
            // colLim | mostRightOne 默认在pos最右侧的1的位置放皇后
            // (leftDiaLim | mostRightOne) << 1:放皇后之后的左斜线的限制
            // 因为要去下一行放皇后了,相当于向左下方移动了,那么(leftDiaLim | mostRightOne) << 1就是下一行放皇后左斜线的限制
            // (rightDiaLim | mostRightOne) >> 1:放皇后之后的右斜线的限制
            // 因为要去下一行放皇后了,相当于向右下方移动了,那么(rightDiaLim | mostRightOne) >> 1就是下一行放皇后右斜线的限制
            ret += BackTracking(limit, colLim | mostRightOne, (leftDiaLim | mostRightOne) << 1, (rightDiaLim | mostRightOne) >> 1);
        }

        return ret;
    }
public:
// totalNQueens只能解决1到32个皇后的问题
// 如果想要解决1到64个皇后的问题,可以将limit的类型改成long long
    int totalNQueens(int n)
    {
        if (n < 1 || n > 32)
        {
            return 0;
        }
        // 保证limit的低n位比特位全为1
        int limit = n == 32 ? -1 : (1 << n) - 1;    
        return BackTracking(limit, 0, 0, 0);
    }
};

回溯法求n皇后问题,数据结构与算法要啸着学,算法,数据结构,c++,N皇后问题

回溯法求n皇后问题,数据结构与算法要啸着学,算法,数据结构,c++,N皇后问题

👉N皇后👈

回溯法求n皇后问题,数据结构与算法要啸着学,算法,数据结构,c++,N皇后问题

N 皇后问题的关键还是判断皇后之间是否会相互攻击。N 皇后这道题和 N皇后II 的思路都是一样的,只是返回的结果不同而已。

class Solution 
{
private:
    vector<vector<string>> ret;

    bool isValid(const vector<int>& record, int row, int col)
    {
        // 第i行的皇后
        // 判断是否和0行到row-1行的皇后共行、共列或者共斜线
        // 如果是,返回false;如果不是,返回true
        // 条件col == record[i]表示当前row行和i行的皇后共列
        // 两个皇后共斜线时,行标差的绝对值等于列标差的绝对值
        // 条件abs(record[i] - col) == abs(row - i)表示两个皇后共斜线
        for(int i = 0; i < row; ++i)
        {
            if(col == record[i] || abs(record[i] - col) == abs(row - i))
                return false;
        }
        return true;
    }

    void BackTracking(int n, int row, vector<string>& chessBoard, vector<int>& record)
    {
        if(row == n)
        {
            ret.push_back(chessBoard);
            return;
        }

        for(int col = 0; col < n; ++col)
        {
            if(isValid(record, row, col))
            {
                // record[row]表示第row行的皇后放在了第col列
                record[row] = col;  
                chessBoard[row][col] = 'Q'; // 放置皇后
                BackTracking(n, row + 1, chessBoard, record);
                chessBoard[row][col] = '.'; // 回溯,撤销皇后
            }
        }
    }
public:
    vector<vector<string>> solveNQueens(int n) 
    {
        ret.clear();    // 防止用同一个对象多次调用该函数
        vector<int> record(n);
        std::vector<std::string> chessBoard(n, std::string(n, '.'));
        BackTracking(n, 0, chessBoard, record);
        return ret;
    }
};

回溯法求n皇后问题,数据结构与算法要啸着学,算法,数据结构,c++,N皇后问题

class Solution 
{
private:
    vector<vector<string>> result;
    // n 为输入的棋盘大小
    // row 是当前递归到棋盘的第几行了
    void backtracking(int n, int row, vector<string>& chessboard) 
    {
        if (row == n) 
        {
            result.push_back(chessboard);
            return;
        }

        for (int col = 0; col < n; col++) 
        {
            if (isValid(row, col, chessboard, n)) { // 验证合法就可以放
                chessboard[row][col] = 'Q'; // 放置皇后
                backtracking(n, row + 1, chessboard);
                chessboard[row][col] = '.'; // 回溯,撤销皇后
            }
        }
    }

    bool isValid(int row, int col, vector<string>& chessboard, int n) 
    {
        // 检查列
        for (int i = 0; i < row; i++) 
        { // 这是一个剪枝
            if (chessboard[i][col] == 'Q') 
            {
                return false;
            }
        }
        // 检查 45度角是否有皇后
        for (int i = row - 1, j = col - 1; i >=0 && j >= 0; i--, j--) 
        {
            if (chessboard[i][j] == 'Q') 
            {
                return false;
            }
        }
        // 检查 135度角是否有皇后
        for(int i = row - 1, j = col + 1; i >= 0 && j < n; i--, j++) 
        {
            if (chessboard[i][j] == 'Q') 
            {
                return false;
            }
        }
        return true;
    }
    
public:
    vector<vector<string>> solveNQueens(int n) 
    {
        result.clear();
        std::vector<std::string> chessboard(n, std::string(n, '.'));
        backtracking(n, 0, chessboard);
        return result;
    }
};

回溯法求n皇后问题,数据结构与算法要啸着学,算法,数据结构,c++,N皇后问题

👉总结👈

本篇博客主要讲解了 N 皇后问题,N 皇后问题算是回溯算法中比较难的题目了,解决 N 皇后问题的关键就是判断皇后之间是否会相互攻击。除此之外,还讲解了用位信息来判断放置皇后的位置限制。那么以上就是本篇博客的全部内容了,如果大家觉得有收获的话,可以点个三连支持一下!谢谢大家!💖💝❣️文章来源地址https://www.toymoban.com/news/detail-792543.html

到了这里,关于【回溯算法篇】N皇后问题的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • N皇后问题详解:回溯算法的应用与实践(dfs)

    题目如上图所示,在一个 n*n 的国际象棋棋盘上怎么摆放能使得皇后互相攻击不到(也就是在 任意一列、一行、一条对角线上都不存在两个皇后 ) 1.DFS 想要解决这个问题,我们可以使用dfs也就是 深度优先遍历 ,深度优先搜索的步骤为先递归到底再回溯上来,顾名思义,df

    2024年03月26日
    浏览(39)
  • 【夜深人静学数据结构与算法】回溯算法

    目录 前言: 回溯算法: 回溯法的常见应用: 回溯法的模板: 回溯法的图解:​ 案例: 77. 组合 - 力扣(LeetCode) 总结:         回溯算法是一个比较抽象的算法,因此我们如果初学者,难度可以说是非常大,因此我们利用这篇来讲解回溯算法的理论知识,后续在力扣刷题里

    2024年02月11日
    浏览(29)
  • 数据结构:地图着色问题——图的应用——回溯法

    目录 前言 一、解决问题的思路 二、存储结构设计 三、代码 1.创建图函数 2.判断色号是否相同函数 3.回溯函数 4.整体代码 总结 本次解决的问题:用图模拟部分地图,对各省进行着色,要求相邻省所使用的颜色不同,并保证使用的颜色总数最少。 先来一张效果图 将邻接矩阵

    2024年02月04日
    浏览(37)
  • DSt:数据结构的最强学习路线之数据结构知识讲解与刷题平台、刷题集合、问题为导向的十大类刷题算法(数组和字符串、栈和队列、二叉树、堆实现、图、哈希表、排序和搜索、动态规划/回溯法/递归/贪心/分治)总

    Algorithm:【算法进阶之路】之算法面试刷题集合—数据结构知识和算法刷题及其平台、问题为导向的十大类刷题算法(数组和字符串、链表、栈和队列、二叉树、堆、图、哈希表、排序和搜索、回溯算法、枚举/递归/分治/动态规划/贪心算法)总结 目录 相关文章

    2024年02月08日
    浏览(42)
  • 算法分析与设计考前冲刺 (算法基础、数据结构与STL、递归和分治、 动态规划、贪心算法、 回溯算法)

    算法分析与设计考前冲刺 算法基础 算法是一系列解决问题的清晰指令,代表着用系统的方法描述解决问题的策略机制。 程序是算法用某种程序设计语言的具体的 具体实现 算法特征: 有穷性(有限步) 确定性 输入 输出 可行性(有限时间) 算法的复杂性: 时间复杂性 和空间复

    2024年02月02日
    浏览(31)
  • 【数据结构】回溯算法公式化解题 leetcode经典题目带刷:全排列、组合、子集

    一、什么是回溯算法 回溯算法(Backtracking Algorithm)是一种解决 组合问题 、 排列问题 、 选择问题 等一类问题的常用算法。它通过尝试所有可能的选择来找到问题的解,当发现当前选择不符合要求时,就回溯到之前的状态,然后尝试其他的选择。 1、基本思想: 从问题的起

    2024年02月11日
    浏览(30)
  • 回溯法求解八皇后问题

    问题提出 :八皇后问题是一个古老而著名的问题。该问题是十九世纪著名的数学家高斯1850 提出在 8x8 格的国际象棋上摆放八皇后,使其不能互相攻击,即任意两个皇后都不能处于同一行、同一列或同一斜线上,问有多少种摆法。高斯认为有76种方案。1854年在柏林的象棋杂志

    2023年04月08日
    浏览(37)
  • 回溯法--n皇后问题

    回溯法有两个模板--子集树、排列树,他们有回溯法的共同特点:深度优先搜索,如果一条路走不通,再退回来(类似递归) 八皇后问题最早是由国际象棋棋手马克斯·贝瑟尔(Max Bezzel)于1848年提出。第一个解在1850年由弗朗兹·诺克(Franz Nauck)给出。并且将其推广为更一般

    2024年02月02日
    浏览(37)
  • 八皇后问题(回溯法)

    目录 什么是八皇后 八皇后问题怎么解决? 什么是回溯法 回溯法的模板 八皇后问题的核心代码 判断皇后位置是否可行 总体实现代码 每日一句: 种一棵树的最好时间是十年前,其次是现在。 八皇后问题(英文:Eight queens),是由国际西洋棋棋手马克斯·贝瑟尔于1848年提出的

    2023年04月09日
    浏览(30)
  • 3.2 回溯法—N皇后问题

    1. 问题描述 在 n × n ntimes n n × n 的棋盘上摆放 n n n 个皇后,使任意两个皇后都不能处于同一行、同一列或同一斜线上 2. 问题分析 下以求解4皇后问题为例,分析4皇后问题的排列树以及回溯过程: 搜索及回溯过程: 解空间树: 3. 算法设计 1. 算法思想 ①用数组x[]存放皇后的

    2024年02月04日
    浏览(27)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包