算法:回溯算法(以解决n皇后问题为例)

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

基本思想:回溯算法的基本思想是:从一条路往前走,能进则进,不能进则退回来,换一条路再试。八皇后问题就是回溯算法的典型,第一步按照顺序放一个皇后,然后第二步符合要求放第2个皇后,如果没有位置符合要求,那么就要改变第一个皇后的位置,重新放第2个皇后的位置,直到找到符合条件的位置就可以了。是一种以深度优先搜索带以跳跃性搜索的算法。

回溯算法说白了就是穷举法,只不过在进行穷举的过程中,用剪枝函数跳过了一些不必要的搜索,跳过了一些不可能到达最终状态的子节点,减少状态空间树节点的生成

那么我们进行回溯算法比较疑惑的地方就是,何为状态空间树,状态空间树如何生成,如何根据问题找出非满足的状态,以及剪枝函数如何进行逻辑设定;

回溯法两种方式的伪代码:

1.递归回溯

void Backtrack(int t){
	if(t > n) Output(x);//Output 记录或者输出可行解
	else{
		for( int i = f(n,t); i <= g(n,t); ++i){//f(n,t)和g(n,t)表示在当前结点未搜索过的子树的起始编号和终止编号
			x[t] = h(i);
			if(constraint(t) && Bound(t)) Backtrack(t+1);//constraint和bound分别是约束函数和界限函数
		}
	}
}
递归实现回溯非常容易理解,但是执行效率没有迭代高,根据需要,开辟大量的内存空间,来进行递归。

2.迭代回溯:

void IterativeBacktrack(void){
 	int t = 1;
 	while(t > 0){
 		if(f(n,t) < g(n,t)){
 			for(int i = f(n,t); i <= g(n,t); ++i){//这个for 是遍历各个值的意思,实际中写成for循环会有逻辑错误
 				x[t] = h(i);
 				if(constraint(t) && bound(t)){
 					if(solution(t)) Output(x);//solution 判断是否已经得到问题的解
 					else t++;
 				}
 				else t--;
 			}
 		}
 	}
 }
 //迭代回溯相比较递归比较难理解,它的迭代过程就是解决问题的逻辑过程,不断进行循环,根据问题的规模,有时候时间复杂度也是不容乐观的。

为了个更好的理解回溯算法的原理,我们以解决n皇后问题为例:

举例:问题就是在 n×n 格的国际象棋上摆放n个皇后,使其不能互相攻击,即任意两个皇后都不能处于同一行、同一列或同一斜线上,问有多少种摆法。
此问题如果用单纯的穷举法解决,会搜索出n^n个搜索结果,穷举的时候从所有皇后都放在第 1 行的方案开始,检验皇后之间是否会相互攻击。如果会,把列 H 的皇后挪一格,验证下一个方案。移到底了就 “进位” 到列 G 的皇后挪一格,列 H 的皇后重新试过全部的 n 行,毫无疑问这种方法效率极低,n过大的话直接会把计算机给跑死,所以我们来看回溯算法。

讲算法之前先展示一下何为状态空间树;

这里我们以四皇后问题解释一下何为状态空间树:
算法:回溯算法(以解决n皇后问题为例)

 

以一个4×4的空棋盘为根,先在棋盘的第一行第一列(1,1)处放置一个皇后1,然后观察皇后2的情况,对于皇后2,在第一列和第二列都无法放置,那么尝试第三列,当我们放置皇后2在(2,3)处时,发现皇后3无法放置,进入了死路,这时候我们进行回溯,将皇后2放置在第四列,然后发现皇后3可以放在(3,2)的这个位置,但是此时问题又出现了,皇后4无法防止,进入死路,那么我们继续回溯,回溯到皇后1应当放置的位置,将皇后1放置在第二列,依次类推,直到找到最后的可成立的一个放置解。这就是该算法的搜索状态空间树。
但是以上的只是一部分,仅仅是皇后1到达第二列为止,其他的方式还可以有搜索状态,但是总的思路是一致的。

进行搜索的过程如下(以四皇后为例)
算法:回溯算法(以解决n皇后问题为例)

 

解决皇后问题比较开心的就是,他的状态空间树的每一个节点就是一个二维空间,代码实现的时候,可以很清晰的进行每一步的搜索,符合计算机存储的逻辑。
到这里我们实际上已经搞清楚了,不满足的状态就是,在每一个皇后位置,同行同列对角线即为不满足,我们搜索的过程一旦遇到此种状态,在进行一步步的搜索时,就要用剪枝函数(此题中就是一个if判断)来进行跳跃回溯搜索。

综上我们大致搞清楚了,进行回溯的时候,回溯到底是一个什么逻辑,回溯难在你需要对问题足够的清晰,搞清楚你这个空间树是子集树还是排序树,亦或者其他,在进行代码实现的时候如何模拟你的搜索过程,采取哪种数据结构,运用递归还是迭代实现过程。(常见的比较难的问题时,可以先写一个递归的伪代码,一般是比较容易想出来的,然后在伪代码基础上进行修改)这是我们大体上的解决过程。总归回溯这种思想是很简明易懂的,但是回溯解决问题的时候,代码实现还是有一定的距离的,这就需要我们大量面对问题,多做多练。

代码实现:
这里只进行了迭代回溯
 文章来源地址https://www.toymoban.com/news/detail-450855.html

#include<stdio.h>
#include<iostream> 
#include<cmath>
using namespace std;
//用一维数组存储,解决行冲突,数组下标为行数,数组值为列数 
int x[10]={0};
int count=0;
bool judge(int k)//判断第k行某个皇后是否发生冲突 ,发生冲突就跳过
{
    int i=1;
    while(i<k)  //循环i到k-1之前的皇后; 
    { 
        if(x[i]==x[k]||abs(x[i]-x[k])==abs(i-k))//存在列冲突或者存在对角线冲突(实际上就是一种剪枝)
            return false;
        i++;
    }
    return true;
}
void queen(int n)
{
    int i,k=1; //k为当前行号,从第一行开始 
    x[1]=0;//x[k]为第k行皇后所放的列号
    while(k>0)
    {
        x[k]++;  //首先从第一列开始判断 
        while(x[k]<=n&&!judge(k))//推导k行到底选择哪一列,如果当前该列不行则下一列,直到成立即可; 
          x[k]++;
        if(x[k]<=n)  
        {
            if(k==n)//输出所有解 
            {
                for(i=1;i<=n;i++)
                    printf("第%d行的皇后:在第%d列  ",i,x[i]);
                count++;
                printf("-------这是其中第%d个解",count);   
                printf("\n");
            }

            else//判断下一行
            {
                k++; x[k]=0;
            }
        }
        else k--;//没找到,回溯
    }
    return ;
}
int main()
{
    int n;
    cout<<"请输入你的n皇后:     "; 
    cin>>n;//n最大值不超过10 
    queen(n);
    return 0;
}

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

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

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

相关文章

  • 回溯法--n皇后问题

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

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

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

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

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

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

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

    2024年02月04日
    浏览(26)
  • 八皇后问题,秒懂递归回溯(有图详解|c语言)

    目录 👸🏻前言 👸🏻题目介绍 👸🏻引入: 👸🏻解决思路: 👸🏻理论存在,实践开始! 👸🏻难点1:如何表示对角线被占领? 👸🏻难点2:如何用递归的方法来放皇后? 👸🏻难点3:如何实现回溯? 👸🏻难点4:如何实现皇后位置的输出? 👸🏻全部代码如下: 👸

    2024年02月02日
    浏览(21)
  • 【算法】回溯:与递归,dfs的同质与分别,剪枝与恢复现场的详细理解,n皇后的回溯解法及算法复杂度分析。

    目录 ​编辑 1.什么是回溯 2.关于剪枝 3.关于恢复现场 4.题目:二叉树的所有路径(凸显恢复现场:切实感受回溯与深搜) 问题分析 ①函数设置为:void Dfs(root) ②函数设置为:void Dfs(root,path) 解题思想:使⽤深度优先遍历(DFS)求解。 代码实现 5.N后问题 问题分析 4皇后的放置

    2024年04月16日
    浏览(29)
  • C#八皇后算法:回溯法 vs 列优先法 vs 行优先法 vs 对角线优先法

    目录 1.八皇后算法(Eight Queens Puzzle) 2.常见的八皇后算法解决方案 (1)列优先法(Column-First Method): (2)行优先法(Row-First Method): (3)对角线优先法(Diagonal-First Method): (4)回溯法(Backtracking):        皇后问题是一个古老而著名的问题,它实质上就是使棋

    2024年03月22日
    浏览(28)
  • 算法思想—枚举、递推、迭代、递归、分治、贪心、动态规划、回溯、模拟、分支定界

    算法思想 枚举(暴力算法) 枚举算法(暴力算法)是一种通过逐一尝试所有可能解来解决问题的算法。它的基本思想是将问题的所有可能答案一一列举出来,并根据一定的判断条件来确定哪些答案是合适的。这种算法通常使用循环来实现,因为需要尝试所有可能的情况。两

    2024年02月01日
    浏览(26)
  • 【算法设计与分析】回溯法解决运动员配对问题(课程设计)

    针对运动员最佳配对问题,本文利用回溯法寻求竞赛优势得分最优解,研究男女运动员最佳配对法,使各组男女双方竞赛优势的总和达到最大。针对这一问题,本题采用的是男运动员选女运动员的方法,构成了一棵排列树。树的结点表示女运动员,排列树的层数表示男运动员

    2024年02月10日
    浏览(55)
  • 湘潭大学 算法设计与分析实验 回溯 动态规划 贪心 模拟退火解决背包问题

    https://download.csdn.net/download/SQ_ZengYX/88620871 测试用例

    2024年02月02日
    浏览(44)

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

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

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

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

二维码1

领取红包

二维码2

领红包