- iOS/Objective-C 元类和类别
- objective-c - -1001 错误,当 NSURLSession 通过 httpproxy 和/etc/hosts
- java - 使用网络类获取 url 地址
- ios - 推送通知中不播放声音
尽管我做了一些简单的练习(例如斐波那契),但我很难理解递归和回溯。所以请允许我在这里展示我的“脑流”:
我读过教科书,知道如果前一个皇后的当前位置消除了将下一个皇后放在下一列的可能性,则可以使用回溯删除前一个皇后。所以这看起来很简单,我需要做的就是将其删除并让程序决定下一个可能的位置。
一段时间后,我发现程序在第 6 个皇后停止,所以我发现如果我简单地删除第 5 个皇后,程序只需将它放回当前位置(即给定前四个皇后第 5 个queen 总是落在同一个地方,这并不奇怪)。所以我想我需要跟踪最后一个女王的位置。
这就是我困惑的时候。如果我要跟踪最后一个皇后的位置(这样当我回溯程序时不允许将皇后放在同一个地方),有两个潜在的困难:
a) 假设我移除了第 5 个皇后,我必须编写代码来决定它的下一个可能位置。这可以通过忽略其当前位置(在被删除之前)并继续在以下行中寻找可能的位置来解决。
b) 我应该跟踪所有以前的皇后吗?好像是这样。假设实际上我必须移除的不是一个皇后,而是两个皇后(或更多),我当然需要跟踪它们的所有当前位置。但这比看起来要复杂得多。
http://www.geeksforgeeks.org/backtracking-set-3-n-queen-problem/
这让我非常惊讶,因为它是如此简单而且有效!唯一的回溯部分是删除最后一个女王!所以问题是:下面的代码如何确保当给定 4 个皇后的位置时,第 5 个皇后不会一次又一次地落在同一个地方?我想我不明白的是你怎么能递归地回溯(比如你需要删除更多的皇后)。递归前进没问题,递归后退怎么办?
/* A recursive utility function to solve N Queen problem */
bool solveNQUtil(int board[N][N], int col)
{
/* base case: If all queens are placed then return true */
if (col >= N)
return true;
/* Consider this column and try placing this queen in all rows
one by one */
for (int i = 0; i < N; i++)
{
/* Check if queen can be placed on board[i][col] */
if ( isSafe(board, i, col) )
{
/* Place this queen in board[i][col] */
board[i][col] = 1;
/* recur to place rest of the queens */
if ( solveNQUtil(board, col + 1) == true )
return true;
/* If placing queen in board[i][col] doesn't lead to a solution
then remove queen from board[i][col] */
board[i][col] = 0; // BACKTRACK
}
}
/* If queen can not be place in any row in this colum col
then return false */
return false;
}
好的。现在我有了一些确实有效的代码,但我主要是根据上面的代码修改了我自己的代码,所以我很不稳定:
bool EightQueen(int& numQueen) {
if (numQueen == 8) {
return true;
}
if (numQueen == 0) {
PlaceQueen(0, 0);
numQueen ++;
EightQueen(numQueen);
}
int row = 0;
for (row = 0; row <= 7; row ++) {
if (CheckThis(row, numQueen)) { //Check if next queen can be put
PlaceQueen(row, numQueen); //Place next queen
numQueen ++;
DisplayQueen();
cout << endl;
if (EightQueen(numQueen)) { //Try next queen
return true;
}
ClearQueen(numQueen - 1);
numQueen --;
}
}
return false;
}
假设 numQueen 为 5,那么在 for 循环中我们将检查是否可以放置第 6 个皇后。正如我们所知,这对所有行都是不可能的,因此该函数返回 false。我假设它然后“缩小”回到它被调用的位置,即当 numQueen 为 4 时。因此调用 ClearQueen(4) 并删除最后一个女王(第 5 个)。显然 for 循环还没有完成,所以我们将尝试下一行以查看它是否允许进一步开发。即我们检查是否可以将第 5 个皇后放在下一行,如果可以,我们将进一步检查是否可以放置第 6 个皇后,依此类推。
是的,它似乎有效,嗯,嗯,是的。
最佳答案
考虑您的初始董事会:
+---+---+---+---+---+---+---+---+
| | | | | | | | |
+---+---+---+---+---+---+---+---+
| | | | | | | | |
+---+---+---+---+---+---+---+---+
| | | | | | | | |
+---+---+---+---+---+---+---+---+
| | | | | | | | |
+---+---+---+---+---+---+---+---+
| | | | | | | | |
+---+---+---+---+---+---+---+---+
| | | | | | | | |
+---+---+---+---+---+---+---+---+
| | | | | | | | |
+---+---+---+---+---+---+---+---+
| | | | | | | | |
+---+---+---+---+---+---+---+---+
当您第一次调用函数时,算法会在第 0 列和第 0 行放置一个皇后,因为您使用 col = 0
调用它因为 for (int i = 0; i < N; i++)
从 0 开始。你的棋盘变成了
+---+---+---+---+---+---+---+---+
| Q | | | | | | | |
+---+---+---+---+---+---+---+---+
| | | | | | | | |
+---+---+---+---+---+---+---+---+
| | | | | | | | |
+---+---+---+---+---+---+---+---+
| | | | | | | | |
+---+---+---+---+---+---+---+---+
| | | | | | | | |
+---+---+---+---+---+---+---+---+
| | | | | | | | |
+---+---+---+---+---+---+---+---+
| | | | | | | | |
+---+---+---+---+---+---+---+---+
| | | | | | | | |
+---+---+---+---+---+---+---+---+
然后,您递归调用该函数,使用 col = 1
,因此您将尝试在 col=1
处放置一个皇后和 line=0
.你得到一个不可能的位置,因为皇后可以互相拿走,所以你继续 for (int i = 0; i < N; i++)
循环并最终成功地在 col=1
放置一个女王和 line=2
,你得到这个板:
+---+---+---+---+---+---+---+---+
| Q | | | | | | | |
+---+---+---+---+---+---+---+---+
| | | | | | | | |
+---+---+---+---+---+---+---+---+
| | Q | | | | | | |
+---+---+---+---+---+---+---+---+
| | | | | | | | |
+---+---+---+---+---+---+---+---+
| | | | | | | | |
+---+---+---+---+---+---+---+---+
| | | | | | | | |
+---+---+---+---+---+---+---+---+
| | | | | | | | |
+---+---+---+---+---+---+---+---+
| | | | | | | | |
+---+---+---+---+---+---+---+---+
现在你继续这样做,递增 col
每次。最终,您将到达此板:
+---+---+---+---+---+---+---+---+
| Q | | | | | | | |
+---+---+---+---+---+---+---+---+
| | | | Q | | | | |
+---+---+---+---+---+---+---+---+
| | Q | | | | | | |
+---+---+---+---+---+---+---+---+
| | | | | Q | | | |
+---+---+---+---+---+---+---+---+
| | | Q | | | | | |
+---+---+---+---+---+---+---+---+
| | | | | | Q | | |
+---+---+---+---+---+---+---+---+
| | | | | | | | |
+---+---+---+---+---+---+---+---+
| | | | | | | Q | |
+---+---+---+---+---+---+---+---+
这里有问题,因为该板不承认第 7 列中的皇后位置。您将不得不回溯。发生的事情是递归函数只到达 return false;
在尝试了列中的所有位置但未找到任何位置之后。当函数返回false时,之前的函数调用会在该行继续执行
if ( solveNQUtil(board, col + 1) == true )
由于调用返回 true,for 循环主体的其余部分将被执行,i
将递增,算法将继续尝试位置。将其视为一组巨大的嵌套 for 循环:
for(int i = 0; i < 8; ++i) {
for(int j = 0; j < 8; ++j) {
//Snip 6 other fors
board[0, i] = 1;
board[1, j] = 1;
//Snip
if(isValid(board)) return board;
//Snip clean up
}
}
用递归函数调用替换。这说明“回溯”实际上只是让先前的递归级别迭代到下一次尝试。在这种情况下,这意味着尝试一个新位置,而在其他应用程序中,这将是尝试下一个生成的移动。
我想你需要明白的是,当你再次调用同一个函数时,之前递归调用的状态并没有丢失。当你到达终点时
if ( solveNQUtil(board, col + 1) == true )
当前函数的状态仍然在栈上,并且为新调用solveNQUtil
创建了一个新的栈帧。 .当该函数返回时,前一个函数可以继续执行,在这种情况下,增加它试图将皇后放在哪一行。
希望这对您有所帮助。解决这些问题的最佳方法是将问题缩小到更小的域(比如更少的皇后区)并使用调试器逐步执行。
关于c++ - 对八皇后中的回溯感到困惑,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/17926069/
在我的类里面,我学习了 Prolog 回溯算法和 Rete forprop 算法,但我也被告知 Rete 可用于进行反向传播。 这是如何运作的?它在哪些方面与 Prolog 回溯相似/不同? 例如,这
两个 friend P1 和 P2 向共同的 friend P3 发送相同的消息 M。 然而由于一些网络损坏,P3 一次只能接收一个字符不知道接收到的字符是属于 P1 还是 P2。 此外,P3 可能会
我最近发了几个理解递归和回溯的问题,我觉得我现在得到了一些东西,并尝试编写一个测试,我确实解决了数独问题,但是当我以另一种格式编写代码时,代码卡了一会儿,返回False,说明这个问题无解。 grid
有人可以指导我或解释如何在 LISP 中执行回溯吗?任何示例或链接将不胜感激。我确实尝试过谷歌,但是他们都没有足够简单的例子让我理解。 谢谢 最佳答案 典型的方法是将不可变状态向下传递到调用堆栈,辅助
我正在使用 apache 2.2.14 运行 Backtrack 5 R2 (ubuntu) 的完全库存安装。我尝试运行一个简单的 index.html 文件,其中包含一些 javascript 代码
如何在 Javascript 中获取回溯? 理想的特征: 入口函数名称,或匿名函数的一些有意义的标识符, 每个级别的参数列表, 行号。 这可以用标准的 ECMAScript 完成吗? 如果没有,是否可
本文首发公众号:小码A梦 回溯算法是一种常见的算法,常见用于解决排列组合、排列问题、搜索问题等算法,在一个搜索空间中寻找所有的可能的解。通过向分支不断尝试获取所有的解,然后找到合适的
Python 是否支持为每个异常/引发/断言显示相同的自定义错误消息(无论代码在哪里中断)? 我目前对它的破解使用了一个装饰器。我有一个函数main它显示回溯很好,但我希望它也打印my_var (在函
输入: 3,4,8,7,3 5,S,7,2,3, 8,5,5,8,10 9,3,3,8,7 6,10,3,G,1 目标是找到从起点(S)到目标(G)的最佳路径。 我们可以向上、向下、向左、向右移动。
我想匹配一个包含“json”(出现超过 2 次)且两个“json”之间没有字符串“from”的字符串。 For example(what I want the string match or not)
我正在尝试使用回溯方法找到熄灯游戏的解决方案。我无法理解此过程的算法。我的方法是枚举从 0 到 2n2 - 1 的所有整数,并将每个整数转换为具有 n*n 位的二进制数。然后,将其分成n2个二进制数字
所以我正在阅读这本书《服从测试山羊》,在学习 Python 时我在第六章中遇到了一个问题。它说我应该能够运行我们在本章和前一章中设置的功能测试,没有错误;但是,我不断收到我不知道如何修复的回溯。 Tr
我需要一些关于 Android 日志文件反混淆的帮助。 问题是如果我有这样的异常: ... 10-16 10:03:10.488: E/AndroidRuntime(25723): Cau
我有一个看起来像这样的表: here | there | -------+-------+ {1,1} | {1,1} | {1,1} | {2,1} | {1,1} | {1,2} |
我写了一小段代码,它应该接受一个字符数组并让它看起来像计算机正在输入文本。很简单,对吧?但是当我运行它时,Terminal 告诉我: *** stack smashing detected ***:
Python 中的堆栈跟踪显示文件路径。有什么方法可以让它们显示完全限定的函数名称吗? 例子: class Foo(object): def bar(self): raise
我决定深入学习回溯的概念,我有以下任务: 给定N个投资者,M个城市,N×M个投资者偏好矩阵P(P[i,j]=1,当第i个投资者希望在第j个城市建矿池;P[i, j] = 0 那么他是中立的,当 P[i
设 E - 图 G 中所有边的集合问题是从G中找到顶点的最小子集S,它满足条件:S = E 中每个顶点的所有出边的总和 换句话说:边是街道,我们可以在顶点上放置路灯。如果我们在一个顶点上放置一盏路灯—
我正在尝试做这个我在查找面试问题时遇到的问题。我们被问及将 r 个硬币放置在 n*m 网格上的方法数量,使得每行和每列至少包含一个硬币。 我想到了一个回溯解决方案,按行主要顺序处理网格中的每个单元格,
我使用 DexGuard混淆。我有来自崩溃日志和映射文件的堆栈跟踪。当我运行 retrace.bat 并为其提供堆栈跟踪和映射文件时,输出仍然是混淆格式。 最佳答案 您是否在使用 ProGuard 的
我是一名优秀的程序员,十分优秀!