【问题标题】:How do I use depth first search to solve this puzzle?如何使用深度优先搜索来解决这个难题?
【发布时间】:2016-03-08 20:13:21
【问题描述】:

所以我做了一个像这样的滑动拼图:

1 0 3
4 2 6
7 5 8

其中 0 代表空白空间,我通过邻接矩阵将其转换为图形。然后我想做的是在图形中搜索并找到 0 的值,然后从该值开始,执行 DFS 并找到从 0 到右下角的路径,当解决的难题看起来像这样时:

1 2 3
4 5 6
7 8 0

这是应该执行 DFS 的代码:

public static boolean SolveNinePuzzle(int[][] B){
        //first section of the code makes the adjacency matrix
        int[][] G = new int[9][9];
        int temp2;
        int temp1;
        for (int i = 0; i < 3; i++){
            for (int j = 0; j < 3; j++){
                getBoardFromIndex(i);
                if (i < 2){
                    temp1 = B[i][j];
                    temp2 = B[i+1][j];
                    G[temp2][temp1] = 1;
                    G[temp1][temp2] = 1;
                    getIndexFromBoard(B);
                }
                if (i > 0){
                    temp1 = B[i][j];
                    temp2 = B[i-1][j];
                    G[temp2][temp1] = 1;
                    G[temp1][temp2] = 1;
                    getIndexFromBoard(B);
                }
                if (j < 2){
                    temp1 = B[i][j];
                    temp2 = B[i][j+1];
                    G[temp2][temp1] = 1;
                    G[temp1][temp2] = 1;
                    getIndexFromBoard(B);
                }
                if (j > 0){
                    temp1 = B[i][j];
                    temp2 = B[i][j-1];
                    G[temp2][temp1] = 1;
                    G[temp1][temp2] = 1;
                    getIndexFromBoard(B);
                }
            }
        }
        printGraph(G);
        System.out.println();
        //Finds out where 0 is and moves the tiles either up down or left or right depending on
        int l = B.length;
        int temp;
        boolean isSolved = true;
        printBoard(B);
        int n = G.length;
        int[] visited = new int[n];
        int visits = 0;
        int c = 0; 
        visited[c] = 1;
        for (int k = 0; k < visited.length; k++) {
            if (visited[k] == 0 && G[c][k] == 1){
                visited[c] = 1;
                c = k;
                k = 0;
            }
        }       

现在它应该穿过所有相邻的顶点。我还没有一种在板上交换值的方法,当它到达右下角时,我也没有搜索停止。基本上,我如何将 DFS 算法应用到带有板的图表上。

【问题讨论】:

  • 在我的任何 BFS 实现中,它总是带有一个队列(普通队列或优先级队列)。我认为您最好学习一些有关队列的知识(不是那么难)并实现 BFS。
  • 我添加了没有堆栈的 DFS 代码,那么实际上可以在没有队列的情况下进行 BFS 吗?如果不可能,我会使用队列,但首先我想知道它是否可能。
  • 据我所知是不可能的。您可以在 SO 上发布另一个问题:Is it possible implement a BFS without queue?
  • @JohnKyle,没有没有堆栈的 DFS 或没有队列的 BFS。您提供的 DFS 实现使用系统堆栈,这是recursion 的结果,因此我们不需要显式定义堆栈。由于任何函数调用都会创建一个系统堆栈(请参阅代码如何执行,或者调用函数时会发生什么),并且没有(固有的)使用队列的方法,队列总是在 BFS 的实现中声明。

标签: java arrays algorithm search breadth-first-search


【解决方案1】:

重复评论:

没有没有堆栈的 DFS 或没有队列的 BFS。你给的 DFS 实现使用系统栈,是递归的结果,所以我们不需要显式定义栈。由于任何函数调用都会创建一个系统堆栈(请参阅代码如何执行,或者调用函数时会发生什么),并且没有(固有的)使用队列的方法,因此将始终在 BFS 的实现中声明队列。

现在,由于您想使用 BFS 解决此问题,我建议您这样做:

首先,为已访问状态创建一个数组,这样您就不会每次都进行冗余调用。有9个!可以存储为字符串(键),(布尔)值映射的可能性,表示是否访问了棋盘状态。

将初始状态标记为已访问。每个棋盘状态可以进行 2(角)、3(边)或 4(中心)移动。进行这些移动并将这些状态推送到队列中,弹出当前状态(并将其标记为已访问)。这样做直到你得到目标状态。 BFS 将自行确定,如果您达到目标状态,它将是,在最少的移动。

【讨论】:

  • 好的,所以我再次更新了我的代码以尝试不同的 DFS 方法。我仍然遇到的问题是,如何在我的板上实现该图中的 DFS?
  • 为什么要使用dfs来解决这个问题?我认为 bfs 是一个更好的解决方案......而且我不确定 dfs 是否会解决这个问题。
【解决方案2】:

由于您的问题被标记为“广度优先搜索”,但您提到的首字母缩写词 DFS 很多,也许需要澄清一下。

假设我们的游戏在任何棋盘状态 (B) 下只有两个可能的走法 (1,2),并且每场游戏最多需要三步来解决。现在,DFS 和 BFS 有何不同?在下面的示例中,“移动”在代码中表示为结果棋盘状态;对于您的游戏,我们可以使用一个字符串,例如"508612347",这也将允许我们创建一个哈希来检查该状态是否已被访问并避免重复相同的搜索。 (另一种存储棋盘状态的方法可以是三个 27 位数字,其中每九位显示当前处于该棋盘位置的数字。然后可以使用位掩码完成移动生成和结束测试。)

深度优先使用栈(后进先出):

starting board-state: B

push possible moves to stack

stack: {B1,B2}

pop B2, push possible moves

stack: {B1,B21,B22}

pop B22, push third move

stack: {B1,B21,B221,B222}

pop B222, it's a third move so check for win

如您所见,在 DFS 中,使用堆栈,我们一次搜索一条路径直至其结束。

广度优先使用队列(先进先出):

starting board-state: B

enqueue possible moves

queue: {B2,B1}

pop B1, enqueue possible moves

queue: {B12,B11,B2}

pop B2, enqueue possible moves

queue: {B22,B21,B12,B11}

...etc.

在 BFS 中,我们使用队列扩展每个级别/深度的所有节点,然后移动到下一个深度。

如果没有启发式方法告诉我们哪些棋盘状态(节点)更适合导致解决方案,我不确定如何判断 DFS 和 BFS 中的哪一个更适合 8 谜题的基本策略。也许一种可能的启发式方法是将带有有序前缀的板视为更接近目标。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2016-04-01
    • 2021-04-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-01-31
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多