我在学年的最后一个项目(我作为CS学生的第一年)的代码中找不到错误。在执行骑士巡回赛问题时,我一直坚持递归。以下是相关文件:https://github.com/sheagunther/tsp161knightstour/blob/master/KnightsTourRecursiveSearch.java
具体来说,我的问题是这部分代码(从第265行开始):
else{
for(int i = 0; i < numberOfPossibleNextMoves; i++){
Cell nextCellToMoveTo = candidateNextMoves.get(i);
int currentRowStorage = currentRow;
int currentColumnStorage = currentColumn;
currentRow = nextCellToMoveTo.row;
currentColumn = nextCellToMoveTo.column;
listOfMoves.add(nextCellToMoveTo);
chessBoard[currentRow][currentColumn] = 1;
currentMoveNumber++;
boolean tourFound = findTour();
if(tourFound){
return true;
}
else{ // Undo the last move just made
backtrackCount++;
chessBoard[currentRow][currentColumn] = -1;
currentRow = currentRowStorage;
currentColumn = currentColumnStorage;
listOfMoves.remove(nextCellToMoveTo);
currentMoveNumber--;
}
}
return false;
这是findTour()的结尾。这是程序的一部分,用于测试当前正方形(也称为单元格)的所有可能移动,如果可以从新移动到正方形完成巡回,则返回true。如果游览不能从广场完成,它会进入其他地方{并撤消移动。这就是我认为的问题所在。
现在,如上面的代码设置,程序陷入无限递归循环。
请注意else{
声明的这一部分:
chessBoard[currentRow][currentColumn] = -1;
currentRow = currentRowStorage;
currentColumn = currentColumnStorage;
这部分代码将chessBoard中的方块更改为-1,这意味着它是未访问的(1 =已访问)。如上所述,新移动的currentRow和currentColumn用于将方块设置为未访问的。然后使用currentRowStorage和currentColumnStorage将这些值重置为先前的跳转值。
如果我将代码更改为
currentRow = currentRowStorage;
currentColumn = currentColumnStorage;
chessBoard[currentRow][currentColumn] = -1;
它成功找到了一个错误的巡回演出,其中最后1/3左右的动作只是在几个方格之间来回跳跃。这是预期的,因为它没有正确处理重置过程。
我怀疑我的问题是由于我在宣布变量的地方。这是我的第一个复杂的递归问题,我不确定我是否正确处理currentRow / Column和currentRow / ColumnStorage之间的切换。我应该在当地或多或少地宣布它们吗?
以下是描述项目的页面:http://cs.usm.maine.edu/~briggs/webPage/c161/projects/KnightsTour.html
以下是要求的相关部分:
如果游览未完成,则findTour确定(可能 空的)从骑士可以到达的空白单元列表 当前单元格,并将此列表存储在本地声明的列表中 变量,candidateNextMoves。这个列表变量至关重要 被声明为方法的本地。如果此列表为空,则表示存在 没办法延长当前的部分游览,所以findTour应该返回 假。如果列表不为空,则findTour尝试扩展 按列表进行每次移动,如下所示。它遍历列表, 并且对于列表中的每个单元格,它将进入下一个单元格, 更新所有L(巡回中的移动列表),B(2D阵列) 董事会的状态(访问过,未访问过),currRow和currCol 反映这一举动。然后递归调用自己,分配 调用本地声明的布尔变量的结果,你 可能会说“成功”。如果成功指定为true,则findTour返回 真正。如果成功是错误的,则findTour撤消它刚刚做出的移动,或者 “回溯”,并尝试候选下一步移动。你会 维护一个初始化的静态int变量backtrackCount 为0,并为每次移动撤消递增。
一个注意事项 - 我调用了我的布尔值'tourFound'而不是'success'。
答案 0 :(得分:5)
通常无限递归的情况下,首先要检查的是你计划如何摆脱它的条件。在这种情况下,只有在
时才能转义if(currentMoveNumber == numberOfMovesOnBoard){
return true;
}
检查您的算法和初始化,以防止currentMoveNumber达到numberOfMovesOnBoard。
提示:在输入递归方法之前,您的起始条件是什么?