如何使用深度优先搜索来解决这个难题?

时间:2015-12-04 00:57:07

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

所以我所做的就是采取一个看起来像这样的滑动拼图:

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算法。

2 个答案:

答案 0 :(得分:4)

重复评论:

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

现在,正如您想使用BFS解决这个问题,我建议采用以下方法:

首先,为访问状态创建一个数组,这样,每次都不会进行冗余调用。有9个!可以存储为string(key),(bool)值映射的可能性,它表示是否访问了一个板状态。

将初始状态标记为已访问。每个电路板状态可以有2个(角落),3个(侧面)或4个(中心)移动。进行这些移动并将这些状态推入队列中,弹出当前状态(并将其标记为已访问)。执行此操作直到达到目标状态。 BFS本身将确保如果你达到目标状态,它将是最小的移动。

答案 1 :(得分:0)

由于您的问题已被标记为“广度优先搜索”,但您提到了许多缩写,DFS,或许需要进行一些澄清。

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

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

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拼图的更好的基本策略。也许一种可能的启发式方法可能是将具有有序前缀的板视为更接近目标。