遍历所有可能的动作

时间:2011-11-04 04:03:14

标签: java recursion

好的,我有点不解决这个问题。

我有一个Puzzle对象,它有一个数量为{1,2,3}的数组和一个表示目标{3,3,0}的数组和一个带有两个整数的移动函数i& j并将其应用于数组。

现在我正在尝试为此编写求解器。因此我们的想法是,我们将所有可能的值应用于i& j并继续应用它直到我们得到所需的目标。

我正在尝试使用递归方法来处理这个问题但是我无法理解的是如何以不同的方式阻止我的递归并找到让我到达目标的最佳“移动集”。

所以可能的行动清单:

(0,1), (0,2), (1,0), (1,2), (2,1), (2,0)

在每次移动之后,我们得到一个新的“数量数组”,我们需要将这些移动应用到那个并检查它们中是否有任何结果导致“目标数组”。

所以我的伪代码是:

solve(puzzle):
   if puzzle.isSolved: return true;
   else:
        solve(puzzle.move(0, 1));
        solve(puzzle.move(0, 2));
        solve(puzzle.move(1, 0));
        solve(puzzle.move(1, 2));
        solve(puzzle.move(2, 0));
        solve(puzzle.move(2, 1));
  • 我们假设puzzle.move函数返回具有新状态的拼图。

现在我确信我在做一些可怕的错误......但我似乎无法用手指指着它。所以任何想法/提示/指示都会受到赞赏。

感谢。

修改

好的,所以要让每个人都清楚这一点:

由于puzzle.move在应用移动后返回拼图,我正在考虑创建一个新拼图,以便递归通过。基本上,需要发生的是每次移动后我们将有一个新的数量数组状态。

因此,在移动(i = 0,j = 1)之后,具有初始量(a,b,c)的拼图具有量(a-a,b + a,c)。我们采取这个新的数量数组并应用下一步(i = 0,j = 2)等等。

但这只是“树”的一部分,还有另一条需要检查的路径,即当我们在初始量上应用移动(i = 0,j = 2)然后从那里继续时。

希望这会有所帮助:)

不过,这个问题被称为水壶问题(http://www.cut-the-knot.org/ctk/Water.shtml)

2 个答案:

答案 0 :(得分:0)

我实际上并不理解你想解决的难题,但我认为不重要

有一些可怕的错误 - 只有当你得到一个积极的解决方案时你才会停止,但你也需要阻止它永远地复制到一个非解决方案。

考虑这段代码将作为一系列步骤执行的操作:

// Solve puzzle
Is puzzle solved? No.
Move puzzle 0,1
// Solve puzzle
Is puzzle solved? No.
Move puzzle 0,1
// Solve puzzle
Is puzzle solved? No.
Move puzzle 0,1

除非移动0,1 .. 0,1 .. 0,1 ..保证最终解决难题,否则此算法永远不会结束。

您需要

  1. 找到一种方法来确定一项行动是否“改善了”这个难题,
  2. 在解决方案明显不起作用时有一些截止日期。

答案 1 :(得分:0)

你试图使解决(puzzle.move)成为递归函数,因此求解必须负责确定要解决的新参数是什么。问题是,如果你传递谜题来解决,就没有办法解决从前一次调用中推断出i和j的值(除非拼图存储它们)。我建议传递i和j的值,然后在递归调用solve之前调用puzzle.move。

solve(puzzle, i, j):
   if solve(puzzle.move(i, j)): return true;
   else:
      j++;
      if (j == i)
         j++;
      if (j > MAX)
         j = 0
         i++;
      if (i > MAX)
         return false;
      solve(puzzle, i, j);

然而,我认为值得注意的是,任何可以通过递归解决的问题都可以在没有递归的情况下调用,所以让我们看看没有它的情况:

i = 0;
j = 1;
solved = false;
while (!solved && i <= MAX)
    while (!solved && j <= MAX)
        solved = puzzle.move(i, j);
        j++;
        if (j == i)
            j++;
        if (j > MAX)
            j = 0
            i++;

在这里,代码稍微简单一点,它避免了所有额外的调用(消耗有限的堆栈空间) - 建议。

相关问题