我正在尝试学习更多关于递归的信息,但不知怎的,我无法解决骑士之旅,我希望有人可以指出我的逻辑错误。
class main {
static int fsize = 5; // board size (5*5)
static int board[][] = new int[fsize][fsize];
static int[] move_x = {1, 2, 2, 1, -1, -2, -2, -1}; // possible moves (x-axis)
static int[] move_y = {-2, -1, 1, 2, 2, 1, -1, -2}; // possible moves (y-axis)
// x = current x coordinate
// y = current y coordinate
static void Solve(int move_number, int x, int y) {
board[x][y] = move_number;
// check whether the knight has been on all filds or not
if (move_number == ((fsize * fsize) - 1)) {
for (int i = 0; i < fsize; i++) {
for (int c = 0; c < fsize; c++) {
System.out.printf("%3d", board[i][c]);
}
System.out.println("\n");
}
}
else {
// calculate new board coordinates
for (int i = 0; i < 8; i++) {
for (int c = 0; c < 8; c++) {
// Check whether the new coordinates are valid or not
if ((x + move_x[i]) >= 0 && (x + move_x[i]) < fsize && (y + move_y[c]) >= 0 && (y + move_y[c]) < fsize) {
// check whether the knight has been on this field or not (-1 = hasn't been here)
if (board[x + move_x[i]][y + move_y[c]] == -1) {
System.out.println("Move: " + move_number + "\n");
// Find next field
Solve(move_number + 1, (x + move_x[i]), (y + move_y[c]));
}
}
}
}
// couldn't find a valid move
board[x][y] = -1;
}
}
public static void main(String[] args) {
for (int i = 0; i < fsize; i++) {
for (int c = 0; c < fsize; c++) {
board[i][c] = -1;
}
}
Solve(0, 0, 0);
}
}
编辑:希望这没关系。我试图运行这个程序,但无法获得超过22个有效的动作。
答案 0 :(得分:2)
我能够通过做两件事来修复你的代码:
for (int i = 0; i < 8; i++)
单级循环检查接下来的8种可能性
board[x][y] = -1;
作为Solve
中的最后一个语句
if
条件board[x][y] = move_number;
修好后,你的作业完成,正确,完成。恭喜!
现在,这就是你所拥有的:
static void Solve(int move_number, int x, int y) {
board[x][y] = move_number;
if (DONE) {
PRINT;
} else {
for (int i = 0; i < 8; i++) {
for (int c = 0; c < 8; c++) {
ATTEMPT_MOVE(i, c); // doesn't make sense!!!
}
}
board[x][y] = -1; // this doesn't belong here!!!
}
}
要修复此代码,您只需执行此操作:
static void Solve(int move_number, int x, int y) {
board[x][y] = move_number;
if (DONE) {
PRINT;
} else {
for (int i = 0; i < 8; i++) {
ATTEMPT_MOVE(i); // now makes more sense!
}
}
board[x][y] = -1; // must undo assignment in first line!
}
答案 1 :(得分:1)
sprung_x
和sprung_y
应该一起移动,因为它们代表骑士的移动。你有c
和i
作为移动这些数组的独立索引,但实际上它应该只是1个变量。我触及内部for
循环,并在i
的任何地方使用了c
。SucheWeg
结束时,您将重新调用的单元格重置为-1。这给我带来了无限循环。删除该线允许它在单元1,2的19次移动中正常完成。根据Knight巡回赛的定义,即1次攻击远离你开始的单元格(0,0),因此代表完整的巡回演出。 / LI>
fsize
5可能无法完成。我用6代替测试。SucheWeg
仍将继续运行,并且需要一种正常终止的方法。你必须允许展开决定,如果你达到了死胡同(我认为-1重置来自#2),但也意识到如果你不小心的话,同样的展开将使它永远存在。 **从方法返回时,应在撤消步骤之前检查电路板是否已满。如果它已满,你就到了最后。只是为了向您展示我使用的代码:
static boolean isFull(int b [][])
{
for(int i = 0; i < b.length; i++)
{
for(int k = 0; k < b[i].length; k++)
{
if(b[i][k] == -1) return false;
}
}
return true;
}
static void SucheWeg(int schrittnummer, int x, int y)
{
board[x][y] = schrittnummer;
if(schrittnummer == ((fsize * fsize) - 1)) return;
for(int i = 0; i < 8; i++)
{
int nextX = x + sprung_x[i];
int nextY = y + sprung_y[i];
// if we can visit the square, visit it
if(nextX >= 0 && nextX < fsize && nextY >= 0 && nextY < fsize)
{
if(board[nextX][nextY] == -1)
{
SucheWeg(schrittnummer + 1, nextX, nextY);
}
}
}
if(isFull(board)) return; // this is how we avoid resetting to -1
board[x][y] = -1; // reset if you get this far, so you can try other routes
}
然后在main
我为我们打印出来:
for(int i = 0; i < fsize; i++)
{
for(int c = 0; c < fsize; c++) System.out.format("%02d ", board[i][c]);
System.out.println("");
}
输出是:
00 33 28 17 30 35
27 18 31 34 21 16
32 01 20 29 10 05
19 26 11 06 15 22
02 07 24 13 04 09
25 12 03 08 23 14
我想说最后一件事 - 这个算法的一个很好的实现会捕获无限循环。如果这实际上是家庭作业,你应该修改它,直到你可以在任何尺寸的板上运行它而不用担心无限循环。目前,如果没有解决方案,它可能会永远运行。
答案 2 :(得分:1)
这就是事情 - 即使第一次尝试移动成功(导致解决方案),您也在尝试不同的有效移动。我会让函数返回一个布尔值,指定它是否达到了解决方案。因此,当您从自身调用函数时,如果它返回false
,则应该只尝试下一个有效移动。此外,当您尝试不同的移动时,您应该清除之前的移动(因为阵列已更改)。
修改强>
class main {
static int fsize = 5; // board size (5*5)
static int board[][] = new int[fsize][fsize];
static int[] move_x = {1, 2, 2, 1, -1, -2, -2, -1}; // possible moves (x-axis)
static int[] move_y = {-2, -1, 1, 2, 2, 1, -1, -2}; // possible moves (y-axis)
// x = current x coordinate
// y = current y coordinate
static boolean solve(int move_number, int x, int y)
{
boolean ret = true;
board[x][y] = move_number;
if(move_number == ((fsize * fsize) - 1))
{
for(int i = 0; i < fsize; i++)
{
for(int c = 0; c < fsize; c++)
{
System.out.printf("%3d", board[i][c]);
}
System.out.println("\n");
}
}
else
{
for(int i = 0; i < 8; i++)
{
if((x + move_x[i]) >= 0 && (x + move_x[i]) < fsize
&& (y + move_y[i]) >= 0
&& (y + move_y[i]) < fsize)
{
if(board[x + move_x[i]][y + move_y[i]] == -1)
{
if (solve(move_number + 1, (x + move_x[i]), (y + move_y[i]))) {
break;
}
}
}
}
ret = false;
board[x][y] = -1;
}
return ret;
}
public static void main(String[] args) {
for (int i = 0; i < fsize; i++) {
for (int c = 0; c < fsize; c++) {
board[i][c] = -1;
}
}
solve(0, 0, 0);
}
}
返回:
0 15 20 9 24
19 10 23 14 21
16 1 18 5 8
11 6 3 22 13
答案 3 :(得分:0)
因为它看起来有点像家庭作业问题,所以我只是从一个提示开始。
move_x
和move_y
是骑士可能的x,y移动。但是,这些可以独立编制索引(i
和c
)。你可能希望重新考虑一下。