【问题标题】:Some trouble with backtracking回溯的一些问题
【发布时间】:2015-06-21 03:10:28
【问题描述】:

在过去几天的大部分时间里,我一直在尝试解决递归回溯问题。从概念上讲,我认为我理解它,但我似乎无法为比 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 的区域)。我从数组 [3] [5] 的 A 开始,并开始尝试从那里填充游戏板的其余部分。我设法在它停止工作之前将其变为字母 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);

  }

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

【问题讨论】:

  • 贴出整个类,我可以把它放到IDE中运行
  • 有三种解决方案?

标签: java recursion backtracking


【解决方案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 次迭代中)

【讨论】:

  • 嗯,好的,谢谢,我会尝试更多的方法/类,应该可以帮助我更好地跟上进度。
猜你喜欢
  • 2020-10-01
  • 2020-12-20
  • 2011-08-09
  • 2019-07-06
  • 2012-07-04
  • 1970-01-01
  • 2016-12-26
相关资源
最近更新 更多