- 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/
我想做的是让 JTextPane 在 JPanel 中占用尽可能多的空间。对于我使用的 UpdateInfoPanel: public class UpdateInfoPanel extends JP
我在 JPanel 中有一个 JTextArea,我想将其与 JScrollPane 一起使用。我正在使用 GridBagLayout。当我运行它时,框架似乎为 JScrollPane 腾出了空间,但
我想在 xcode 中实现以下功能。 我有一个 View Controller 。在这个 UIViewController 中,我有一个 UITabBar。它们下面是一个 UIView。将 UITab
有谁知道Firebird 2.5有没有类似于SQL中“STUFF”函数的功能? 我有一个包含父用户记录的表,另一个表包含与父相关的子用户记录。我希望能够提取用户拥有的“ROLES”的逗号分隔字符串,而
我想使用 JSON 作为 mirth channel 的输入和输出,例如详细信息保存在数据库中或创建 HL7 消息。 简而言之,输入为 JSON 解析它并输出为任何格式。 最佳答案 var objec
通常我会使用 R 并执行 merge.by,但这个文件似乎太大了,部门中的任何一台计算机都无法处理它! (任何从事遗传学工作的人的附加信息)本质上,插补似乎删除了 snp ID 的 rs 数字,我只剩
我有一个以前可能被问过的问题,但我很难找到正确的描述。我希望有人能帮助我。 在下面的代码中,我设置了varprice,我想添加javascript变量accu_id以通过rails在我的数据库中查找记
我有一个简单的 SVG 文件,在 Firefox 中可以正常查看 - 它的一些包装文本使用 foreignObject 包含一些 HTML - 文本包装在 div 中:
所以我正在为学校编写一个 Ruby 程序,如果某个值是 1 或 3,则将 bool 值更改为 true,如果是 0 或 2,则更改为 false。由于我有 Java 背景,所以我认为这段代码应该有效:
我做了什么: 我在这些账户之间创建了 VPC 对等连接 互联网网关也连接到每个 VPC 还配置了路由表(以允许来自双方的流量) 情况1: 当这两个 VPC 在同一个账户中时,我成功测试了从另一个 La
我有一个名为 contacts 的表: user_id contact_id 10294 10295 10294 10293 10293 10294 102
我正在使用 Magento 中的新模板。为避免重复代码,我想为每个产品预览使用相同的子模板。 特别是我做了这样一个展示: $products = Mage::getModel('catalog/pro
“for”是否总是检查协议(protocol)中定义的每个函数中第一个参数的类型? 编辑(改写): 当协议(protocol)方法只有一个参数时,根据该单个参数的类型(直接或任意)找到实现。当协议(p
我想从我的 PHP 代码中调用 JavaScript 函数。我通过使用以下方法实现了这一点: echo ' drawChart($id); '; 这工作正常,但我想从我的 PHP 代码中获取数据,我使
这个问题已经有答案了: Event binding on dynamically created elements? (23 个回答) 已关闭 5 年前。 我有一个动态表单,我想在其中附加一些其他 h
我正在尝试找到一种解决方案,以在 componentDidMount 中的映射项上使用 setState。 我正在使用 GraphQL连同 Gatsby返回许多 data 项目,但要求在特定的 pat
我在 ScrollView 中有一个 View 。只要用户按住该 View ,我想每 80 毫秒调用一次方法。这是我已经实现的: final Runnable vibrate = new Runnab
我用 jni 开发了一个 android 应用程序。我在 GetStringUTFChars 的 dvmDecodeIndirectRef 中得到了一个 dvmabort。我只中止了一次。 为什么会这
当我到达我的 Activity 时,我调用 FragmentPagerAdapter 来处理我的不同选项卡。在我的一个选项卡中,我想显示一个 RecyclerView,但他从未出现过,有了断点,我看到
当我按下 Activity 中的按钮时,会弹出一个 DialogFragment。在对话框 fragment 中,有一个看起来像普通 ListView 的 RecyclerView。 我想要的行为是当
我是一名优秀的程序员,十分优秀!