回溯有些麻烦

时间:2015-04-15 08:37:04

标签: java recursion backtracking

过去几天我花了很多时间试图绕过递归的回溯。从概念上讲,我认为我理解它,但我似乎无法实现它,而不是像n-queen这样的事情。挑战是通过填写以A开头并以Y结尾的字母来解决5x5拼图。每个字母必须与其前后的字母相邻(对角线计为相邻字母)。

此外,围绕拼图的边缘是"线索"定义后续字母必须与"游戏板的最外边缘相关的位置"原样。例如,字母B必须水平或垂直出现" B"在董事会的线索部分,而字母" P"将出现在" P"对角线上。在董事会的线索部分,因为" P"在一个角落里。我目前把电路板作为一个7x7阵列布局,其中包括外部的线索,以保持组织如下。

 T X Y N F E J 
 V 0 0 0 0 0 O 
 R 0 0 0 0 0 Q 
 L 0 0 0 0 0 C  
 K 0 0 0 0 0 H 
 G 0 0 0 0 0 I 
 P W U S D B M 

" A"可以出现在棋盘内的任何地方(标有0' s的区域)。我从A开始在阵列[3] [5]开始尝试从那里填充其余的游戏板。我设法在它停止工作之前写入字母F,所以我的电路板目前看起来像这样。

  T X Y N F E J 
  V 0 0 0 F E O 
  R 0 0 0 D B Q 
  L 0 0 0 C A C 
  K 0 0 0 0 0 H 
  G 0 0 0 0 0 I 
  P W U S D B M 

以下是目前的模式代码。我目前正在使用字符堆栈来保存所有字母(顶部为B,底部为Y):

  public boolean solver(int currRow, int currCol){ //sets current focus
  nt column=0;
  int row=0;

  if(abcs.empty()) //the base case, returns true when abc stack is empty
     return true;

  for(row=currRow-1;row<=(currRow+1);row++) //cycles through the spaces
                                            //adjacent to the focus spot
        {

        for(column=currCol-1;column<=(currCol+1);column++)
           {

           if(promising(row,column,abcs.peek())) //invokes a method
              {                     // designed to check the clues
              prevChar=array[row][column]; //saves char just in case
              array[row][column]=abcs.pop(); //pops stack and adds to board

              solver(row,column); //my attempt at recursion
              }
           else    //haven't quite figured out what needs to be here
              ;     



             } 
           }


        display();

        abcs.push(prevChar);   //these steps are for replacing the array
                            //values if no legit adjacent spots are found
        if(array[currRow][currCol]!='A') //(unsure if necessary)
           array[currRow][currCol]='0';



     return(false);}  //the false return that is supposed to begin                        
                      //backtracking
 public void display() //prints the 2d array in a grid
  {
  String holder="";
  for(int i = 0; i<7;i++)
     {
     for(int k = 0; k<7; k++)
        {
        holder=holder + array[i][k] + " ";
        }
     holder=holder + "\n";
     }
  System.out.println(holder);

  }

我研究过回溯,似乎这个问题介于一般的迷宫遍历&#34;和&#34;数独&#34;。似乎有必要存储我之前访问过的网格的哪些部分,但是我还不确定哪种方法最适合它,同时仍然认为这是递归。我很容易被告知,你已经以完全错误的方式解决了这个问题,因为我老实说不知道还有什么可以尝试。任何建议将不胜感激。

1 个答案:

答案 0 :(得分:1)

基本上,回溯的工作原理如下:

-Pick a starting point
-While the problem isn't solved
       -For each path from the starting point
             -Set that as the starting point and recurse
             -If it returns true, then return true
       -Undo the current move (since none of the options panned out)
       -Return false

我无法清楚地知道你“撤消”的位置?您可以通过在每次移动时将状态推送到堆栈并在撤消时弹出它,或者通过撤消板上的移动来实现此操作。

我会重新开始尝试使Java代码模仿上面的算法。另外,我会向它介绍更多面向对象的代码。

您可以实施isSolved()getValidMoves()和主要方法doNextMove()等方法,这些方法将被称为递归调用。

如果我必须实现这个,我会创建类似于包含状态的Board类。

Board类可以使用getValidMoves()isSolved()doMove()方法。

你的BackTracker类应该实现递归逻辑,看起来像这样。

public static void iterate(Board b, char c)
{
    List<Move> moves = b.getValidMoves(c);


    for (Move m : moves)
    {
        Board n = Board.copyOf(b);
        n.doMove(m, c);
        if (n.isSolved())
        {
            System.out.println(n.toString());
        }
        else
        {
            iterate(n, (char) (c+1));
        }
    }

}
public static void main(String[] args) {

    Board b = Board.create();
    iterate(b, 'a');
}

顺便说一下。我有3个解决方案。 (在7296次迭代中)