8皇后问题是一道非常经典的题目。当初我是怎么也不能明白怎么用回溯法来解此题的。现在似乎明白些了,先贴出来。
题目大家都是知道的,就不多说了。其实,题目就是要找出所有的可能情况,然后排除其中不符合条件的情况,剩下的情况即为所要求的。怎么找出所有的情况呢?对于8皇后,我们可以使用穷举法,穷举出每一种放置方法,然后判断是否符合题意。如果每次放一行,那就需要8重循环才可以解出来。虽然空间复杂度可以小到为0,但是时间复杂度太高。
书中一般使用回溯法来解此题。仔细分析此题,可以发现:每一行上只能放置一个皇后,然后后面每行放置的皇后,不能与前面的行上放置的皇后在同一列上或者同一对角线上。所以用一个一维数组就可以存放在棋盘上放置的皇后的行列信息:一维数组的第i个位置存放的数值j就表示,在棋盘的第i行、第j列上放着一个皇后。棋盘的一行就用一个元素来表示,所以不能在同一行就不用判断了。知道了皇后在棋盘的行列位置后,判断是否符合后面的两个条件也比较容易了(对角线只要仔细分析下,两个二维坐标点如果在对角线上,他们的行列坐标将会满足何种情况即可)。
搞定了数据结构,接着就要考虑如何进行回溯搜索了。回溯一般借用递归来实现。用我的一个ACM非常牛的一个同学的话来说:回溯就是让计算机自动的去搜索,碰到符合的情况就结束或者保存起来,在一条路径上走到尽头也不能找出解,就回到原来的岔路口,选择一条以前没有走过的路继续探测,直到找到解或者走完所有路径为止。就这一点,回溯和所谓的DFS(深度优先搜索)是一样的。那现在的关键是,怎么实现搜索呢?回溯既然一般使用递归来实现,那个这个递归调用该如何来写呢?我现在的理解就是,进行回溯搜索都会有一系列的步骤,每一步都会进行一些查找。而每一步的情况除了输入会不一样之外,其他的情况都是一致的。这就刚好满足了递归调用的需求。通过把递归结束的条件设置到搜索的最后一步,就可以借用递归的特性来回溯了。因为合法的递归调用总是要回到它的上一层调用的,那么在回溯搜索中,回到上一层调用就是回到了前一个步骤。当在当前步骤找不到一种符合条件情况时,那么后续情况也就不用考虑了,所以就让递归调用返回上一层(也就是回到前一个步骤)找一个以前没有尝试过的情况继续进行。当然有时候为了能够正常的进行继续搜索,需要恢复以前的调用环境。
下面贴出8皇后问题的代码:
#include <iostream>
#include <cmath>
using namespace std;
void PrintResult(int *arr, int n)
{
for (int i = 1; i != n + 1; ++i)
cout << "(" << i << "," << arr[i] << ")" << " ";
cout << endl;
}
bool Verify(int *arr, int i)
{
/* 和前面的i - 1行比较,看当前放置位置是否合法?*/
for (int k = 1; k != i; ++k)
if (arr[k] == arr[i] || abs(i - k) == abs(arr[i] - arr[k]))
return false;
return true;
}
/* 虽然只用了一个一维数组,但是其中已经保存了足够的信息。
因为每一行只能放一个皇后,所以一维数组的第i个位置存放的
是在第i行的哪一列(第j列)上放置了皇后。这个递归函数
每次处理一行,直到第n行(下标从1开始)。*/
void NQueens(int *arr, int i, int n)
{
/* 尝试着在第i行的第j列放置一个皇后。*/
for (int j = 1; j != n + 1; ++j)
{
arr[i] = j;
if (Verify(arr, i))
{
/* 这个递归程序的结束条件是第n行放置完毕,
所以,当递归函数从调用NQueens(arr, i + 1, n)返回时,
就是回到了第i行,继续搜索合适的位置。当第i + 1行的
所有位置都不能满足的时候,上面的调用就会返回,也就
是进行了所谓的回溯。这个回溯不需要显示的恢复以前的
调用环境,因为所需要的信息没有被破坏。*/
if (i == n)
PrintResult(arr, n);
else
NQueens(arr, i + 1, n);
}
}
}
int main()
{
int n;
cin >> n;
int *arr = new int[n + 1];
NQueens(arr, 1, n);
return 0;
}
分享到:
相关推荐
N皇后问题,回溯法,递归
回溯法递归实现和非递归实现.解用向量表示,解分量集合有1、2两个元素,一表示放入背包,二表示不放入背包。具有一般性。
n后问题---递归回溯法 n后问题---递归回溯法 n后问题---递归回溯法 n后问题---递归回溯法 n后问题---递归回溯法 n后问题---递归回溯法 n后问题---递归回溯法 n后问题---递归回溯法 n后问题---递归回溯法 n后问题---...
**总的来说,利用回溯法解决n皇后问题,关键在于理解回溯算法的原理,正确地设计递归函数,以及有效地实施剪枝策略。通过C++编程,我们可以将这些思想转化为可执行的代码,并在VC6.0环境下进行测试和调试。**
N皇后问题的回溯法求解是一个典型的递归加回溯的应用案例。通过递归的方式尝试在每一行放置一个皇后,并利用回溯机制撤销不成功的决策,最终可以找到所有可行的解决方案。此方法虽然简单直观,但在N较大时可能会面临...
### n皇后问题回溯法解析 #### 一、问题背景及定义 n皇后问题是一个经典的计算机...通过以上分析,我们可以看到回溯法是解决n皇后问题的一种有效方法,而C++语言的强大功能和灵活性使得实现这类算法变得相对简单。
N皇后问题(回溯法) N皇后问题是计算机科学中的一类经典问题,它是指在一个NxN的棋盘上,如何将N个皇后摆放的方式,使得每个皇后都不会攻击到其他皇后。这个问题可以使用回溯法来解决。 回溯法是一种常用的搜索...
通过阅读和理解这些代码,你可以更深入地了解递归和回溯在解决N皇后问题中的具体应用。 总的来说,N皇后问题的解决方法展示了如何利用递归和回溯策略来处理复杂的约束问题。递归方法直观且易于理解,但可能会有较高...
总结起来,"C#控制台回溯法实现n皇后问题"是一个利用C#编程语言在控制台环境下,通过回溯算法解决经典计算机科学问题的实例。它涉及到的主要知识点包括:回溯法的概念和实现,递归算法,二维数组的使用,以及控制台...
n皇后问题相信大家早已熟悉了,用回溯法解,那是相当的简单。
总结,通过回溯法解决N皇后问题,需要理解回溯法的基本思想,实现冲突检测和回溯策略,并能够将算法结果通过Java Swing界面展示出来。提供的压缩包文件可能包含了实现这个功能的源代码,可以进一步学习和理解如何将...
在提供的文件"n后问题.cpp"中,可能包含了使用C++语言实现的n皇后问题的回溯法解决方案。代码通常会包含一个主函数,负责初始化和调用递归函数,以及一个递归函数,用于实际的皇后放置和回溯操作。通过分析这个文件...
总结来说,八数码问题的解法通过回溯法结合递归策略,能够在大量的可能性中高效地寻找解决方案。这种算法适用于许多其他类似的组合优化问题,如数独、旅行商问题等。通过理解并掌握这种算法,我们可以更好地应对复杂...
通过以上分析,我们可以看到,回溯递归是解决N皇后问题的关键策略。递归负责逐行处理皇后放置,而回溯则在遇到冲突时撤销操作,探索其他可能性。这种方法简洁高效,能找出所有可能的解决方案,对于理解和实践问题...
本主题聚焦于C++类库与算法的应用,特别是标准模板库(STL)中的算法,并通过一个具体的实例——皇后问题的回溯法实现来深入探讨。 皇后问题是一个经典的计算机科学问题,它要求在棋盘上放置N个皇后,使得任意两个...
本资源是数据结构中利用非递归法实现n皇后问题的一个C++代码,仅供参考,欢迎指正
**回溯法是一种在搜索解决问题时采用的有效算法,...**总的来说,通过理解并分析`n皇后问题.cpp`源代码,我们可以学习到如何利用C++和回溯法解决复杂的问题。这不仅有助于提升编程技能,还能培养解决问题的思维能力。**
通过这种方式,我们可以使用C++的回溯法解决N皇后问题,深入理解回溯法的基本思想,并掌握其在实际问题中的应用。这种方法不仅可以解决N皇后问题,还可以扩展到其他类似的问题,如八数码难题、迷宫问题等。
回溯通常通过递归实现,每次递归尝试将皇后移动到下一列,直到找到解决方案或所有列都试过。 4. 深度优先搜索:在N-QUEEN函数中,从第一行开始,对于每一行k,尝试所有可能的列xk,使用PLACE函数检查当前位置是否...
总的来说,这个项目提供了使用C++实现回溯法解决n皇后问题的一个实例,它涉及了递归、回溯、深度优先搜索等编程与算法知识。通过理解和分析这段代码,不仅可以加深对回溯法的理解,也能提升C++编程能力,特别是处理...