当前位置: 首页 > 知识库问答 >
问题:

用递归法解佩格纸牌

经骁
2023-03-14

我目前面临的问题是,我的代码无法解决peg纸牌板的不同变体。我的测试程序测试了4个简单的可解电路板。(1移动解决方案)向上移动一次,向下移动一次,向左移动一次,向右移动一次。我的代码解决了这些问题,同时测试了一个无法解决的电路板。我面临的问题是如何解决更复杂的问题,比如加号、菱形和标准板。

我不太确定如何将递归添加到这个问题中。我在solveHelp方法调用setupMove的末尾添加了它,但这破坏了我的其余代码。不允许简单的解决方案被正确地解决。

对这个问题应用递归的最好方法是什么?

public static boolean setupMove(
        boolean[][] pegs, int startX, int startY, int jumpX, int jumpY, int endX, int endY) {

    // Look at all of the pegs in the board
    for (int x = 0; x < pegs.length; x++) {
        for (int y = 0; y < pegs[x].length; y++) {
            if (pegs[x][y]) {
                startX = x;
                startY = y;

                if (startX <= 5 && pegs[startX][startY] == true
                        && pegs[startX + 1][startY] == true && pegs[startX + 2][startY] == false) {
                    tryMove(pegs, startX, startY, startX + 1, startY, startX + 2, startY);
                }
                if (startX >= 2 && pegs[startX][startY] == true 
                        && pegs[startX - 1][startY] == true && pegs[startX - 2][startY] == false) {
                    tryMove(pegs, startX, startY, startX - 1, startY, startX - 2, startY);
                }
                if (startY <= 5 && pegs[startX][startY] == true 
                        && pegs[startX][startY + 1] == true && pegs[startX][startY + 2] == false) {
                    tryMove(pegs, startX, startY, startX, startY + 1, startX, startY + 2);
                }
                if (startY >= 2 && pegs[startX][startY] == true 
                        && pegs[startX][startY - 1] == true && pegs[startX][startY - 2] == false) {
                    tryMove(pegs, startX, startY, startX, startY - 1, startX, startY - 2);
                }
            }
        }
    }
    if (win) {
        return true;
    } else {
        solution = null;
        return false;
    }
}

public static void tryMove(
        boolean[][] pegs, int startX, int startY, int jumpX, int jumpY, int endX, int endY) {
    pegs[startX][startY] = false;
    pegs[jumpX][jumpY] = false;
    pegs[endX][endY] = true;
    prevSolution = solution;
    solution = solution + " " + startY + " " + startX + " " + endY + " " + endX;
    solveHelp(pegs, startX, startY, jumpX, jumpY, endX, endY);
}

public static void solveHelp(
        boolean[][] pegs, int startX, int startY, int jumpX, int jumpY, int endX, int endY) {
    for (int x = 0; x < pegs.length; x++) {
        for (int y = 0; y < pegs[x].length; y++) {
            if (pegs[x][y]) {
                pegCount++;
            }
        }
    }
    if (pegs[3][3] && pegCount == 1) {
        // WE WIN!!!
        win = true;
    }

    if ((!win && pegCount == 1) || (endX < 0 || endY < 0 
            || endX >= pegs.length || endY >= pegs[endX].length 
            || (endX < 2 && endY < 2) || (endX >= 5 && endY < 2) 
            || (endX < 2 && endY >= 5) || (endX >= 5 && endY >= 5))) {
        pegs[startX][startY] = true;
        pegs[jumpX][jumpY] = true;
        pegs[endX][endY] = false;
        pegCount++;
        solution = prevSolution;
    }
    pegCount = 0;
}

共有1个答案

卞安邦
2023-03-14

递归地表达一个算法就是把它写成一种方法,通过把它转换成稍微简单一点的版本来解决问题。然后递归调用相同的方法来解决这些问题。

该方法最终通过检查一个或多个“基本情况”来停止自调用链问题非常简单,答案显而易见。

您选择了一个不允许递归解决方案的方法签名。这件事没有耻辱可言。获得一个可用的递归方法签名是一项通过大量实践获得的技能。

在这里,如果该方法只接受一个纸牌棋盘配置和它包含的桩号,比如N,你会做得更好。然后对于每一个合法的跳转方式,它会跳转,产生一个新版本的棋盘和N-1个桩号。它呼吁自己解决这个新的、较小的问题。基本情况是1个peg,这当然意味着你赢了。

void play(boolean [][] board, int nPegs) {
  if (nPegs == 1) { System.out.println("We win!"); System.exit(0); }
  else {
    for (int i = 0; i < 7; ++i) { // i is the row
      for (int j = 0; j < 7; ++j) { // j is the column
        if (!board[i][j]) continue; // No pin. Skip this position
        if (isLegalToJumpEast(board, i, j)) {
          // Do the jump east and solve recursively.
          board[i][j] = board[i][j + 1] = false;
          board[i][j + 2] = true;
          play(board, n - 1);
          // Undo the jump so the search can continue.
          board[i][j] = board[i][j + 1] = true;
          board[i][j + 2] = false;
        }
        // .. similar if()'s for West, North, and South.
      }
    }
  }
}

当然,这会跳过问题中有趣的部分,比如一旦找到解决方案就打印出来。

此外,这种算法非常浪费,因为它会多次重新评估相同的董事会配置。这是完全没有必要的。一旦你探索了给定董事会的所有可能结果,再做一次就没有意义了。

你可以通过“记忆”递归方法来解决这个问题。在方法开始时,检查一组已经探索过的电路板,如果找到当前的电路板,则什么也不做。否则在集合中保存一份副本并继续。

Java提供了在集中复制和保存2d矩阵的详细信息

 类似资料:
  • 数学归纳法 数学归纳法(mathematical induction)是一种数学证明方法,常用于证明命题(命题是对某个现象的描述)在自然数范围内成立。随着现代数学的发展,自然数范围内的证明实际上构成了许多其他领域(比如数学分析)的基础,所以数学归纳法对于整个数学体系至关重要。 数学归纳法本身非常简单。如果我们想要证明某个命题对于自然数n都成立,那么: 第一步 证明命题对于n = 1成立。 第二步

  • 本文向大家介绍Java中的递归详解(用递归实现99乘法表来讲解),包括了Java中的递归详解(用递归实现99乘法表来讲解)的使用技巧和注意事项,需要的朋友参考一下 1:普通实现99乘法表太简单,是个程序员都会,实现如下: 2:用递归方式实现 99乘法表 代码如下: 递归的方式调用图示: 每一个方法的调用都会产生一个栈帧,压入到方法栈,当递归调用的时候,方法栈中栈帧的图示和上图类似。 去掉方法中栈帧

  • 问题内容: 编辑:“ 我从’erickson’那里收到了一个非常相关的答案,但是存在一个附带问题(向上投射?),这个问题在我的原始示例中并未明确涵盖,并且无法用他的答案解决。我将该示例扩展到涵盖了另一个问题,我已在本文结尾处将其包括在内。感谢您的帮助。 我目前面临Java泛型的问题,该问题与所谓的“好奇地重复的通用模式”有关。在阅读了Jon Skeet对这个问题“ java枚举定义”的答案之后,我

  • 对于,我被赋予和。 现在给定N、A、B、C和X,如何有效地找到所有N个元素? 我需要把这N个元素分成2组,其中最大的元素在第一组,第二大的元素在第二组,第三大的元素在第一组,以此类推。。。最后需要找到两个集合元素之和的绝对差。 我可以在不计算所有元素的情况下找到这个差异吗?因为N可以大到最大值为100。

  • 我试图在Scala中使用递归来解决背包问题,但我的要求是显示选择哪些项目保存在背包中。表示背包大小。 我的代码如下: 如何知道选择哪些物品放在背包里?

  • 我遇到了一个问题,就是如何找到所有可能的组合来改变一张5欧元的纸币。我写了一个程序,不能得到正确的组合数。 我的方法受到以下启发: 500分200、200、100;200分100、100;100分50、50。 在我编写代码之后,我意识到100也可以分为5 20。我知道这是一个错误,但我不知道如何使用我的方法修复。 我的方法是递归的,如下所示,它只检查第一个数字,并相应地对其进行除法。 以下是我尝试