简体   繁体   English

Java:使用BFS查找最短路径时出现问题

[英]Java: Trouble when using BFS to find a shortest path

Class State : 阶级状态:

import java.util.Arrays;

public class State {
private int data[][];

public int[][] getData() {
    return data;
}

public void setData(int[][] data) {
    this.data = data;
}
public void swap(int row1, int col1, int row2, int col2){
    int temp = this.data[row1][col1];
    this.data[row1][col1] = this.data[row2][col2];
    this.data[row2][col2] = temp;

}
public State copyState() {
    int height = this.data.length;
    int width = this.data[0].length;
    int[][] temp = new int[height][width];
    for (int i = 0; i < height; i++) {
        for(int j=0; j< width; j++){
            temp[i][j] = this.data[i][j];
        }
    }
    State target = new State(temp);
    return target;      
}

public State(int[][] data) {
    super();
    this.data = data;
}
}

Class Node : 类节点:

public class Node {
private State state;
private Node parent;
private ArrayList<Node> children;

public Node(State state){
    this.state = state;
    parent = null;
    children = new ArrayList<>();
}

public State getState() {
    return state;
}
public void setState(State state) {
    this.state = state;
}
public Node getParent() {
    return parent;
}
public void setParent(Node parent) {
    this.parent = parent;
}
public ArrayList<Node> getChildren() {
    return children;
}
public void addChild(Node node){
    node.setParent(this);
    this.children.add(node);
}
public ArrayList<Node> returnSuccessor(){ // generate all possible moves(has been tested - work well)
    ArrayList<Node> result = new ArrayList<>();
    int[][] matrix = this.getState().getData();
    int row = matrix.length;
    int col = matrix[0].length;
    int rowX = 0;
    int colX = 0;

    for(int i=0; i<row; i++){
        for(int j=0; j<col; j++){
            if ( matrix[i][j] == 0) {
                rowX = i;
                colX = j;
            }
        }
    }

    if( (colX-1) >= 0 ){
        State temp = this.getState().copyState();
        temp.swap(rowX, colX, rowX, colX-1);
        Node left = new Node(temp);
        result.add(left);
    }
    if ( (colX+1) < col ){
        State temp = this.getState().copyState();
        temp.swap(rowX, colX, rowX, colX+1);
        Node right = new Node(temp);
        result.add(right);
    }
    if ( (rowX-1) >= 0 ){
        State temp = this.getState().copyState();
        temp.swap(rowX, colX, rowX-1, colX);
        Node top = new Node(temp);
        result.add(top);
    }
    if ( (rowX+1) < row ){
        State temp = this.getState().copyState();
        temp.swap(rowX, colX, rowX+1, colX);
        Node down = new Node(temp);
        result.add(down);
    }

    return result;
}


public void printState(){
    System.out.println(Arrays.deepToString(this.getState().getData()));
}

public boolean equal(Node node){ // check whether 2 nodes are the same
    return Arrays.deepEquals(this.getState().getData(), node.getState().getData());
}
public boolean checkTree(Node node){ // check whether a node has been added into the tree or not
    if (this.equal(node)) { 
        return true;
    }
    ArrayList<Node> children = this.getChildren();
    boolean result = false;
    if (children.size() > 0){
        for(int i=0; result == false && i< children.size(); i++){
            result = children.get(i).checkTree(node);
        }
    }
    return result;
}
}

Class main : 班级主要:

public class main {
public static void BFS(Node root, Node goal) throws InterruptedException{
Queue<Node> queue = new LinkedList<Node>();
queue.add(root);
while(queue.size()>0){
    Node temp = queue.poll();
    if (temp.equal(goal)) {
        goal.setParent(temp.getParent());
        break;
    }
    else{
        ArrayList<Node> successor = temp.returnSuccessor();
        for(int i=0; i< successor.size(); i++){
            boolean check = root.checkTree(successor.get(i));
            if (check == false){
                queue.add(successor.get(i));
                temp.addChild(successor.get(i));
            }
        }
    }
  }
}
public static void main(String[] args) throws InterruptedException {
    int[][] initialState = { {2,1}, {3,0} };
    int[][] goalState = { {0,1}, {2,3} };
    Node root = new Node(new State(initialState));
    Node goal = new Node(new State(goalState));
    BFS(root,goal);
    Node temp = goal;
    if(temp.getParent() ==  null){
        System.out.println("There is no such a way to go from the initial state to the goal state");
    }
    else{
        ArrayList<Node> listSteps = new ArrayList<>();
        while(temp != null){
            listSteps.add(temp);
            temp = temp.getParent();
    }
        for (int i=listSteps.size()-1; i>=0; i--){
            listSteps.get(i).printState();
            Thread.sleep(1000);
        }
        int numSteps = listSteps.size()-1;
        System.out.println("Number of steps: " + numSteps);
    }
}

I want to find a shortest path from the initial state to goal state ( nearly the same as n-puzzle game ) 我想找到从初始状态到目标状态的最短路径(几乎与n-puzzle游戏相同)

When i try running my program with 2x2 size puzzle as an input, it works well. 当我尝试使用2x2大小的拼图作为输入运行我的程序时,它运行良好。

For example with input : 例如输入:

int[][] initialState = { {2,1}, {3,0} };
int[][] goalState = { {0,1}, {2,3} };

The result will be: 结果将是:

[[2, 1], [3, 0]]
[[2, 1], [0, 3]]
[[0, 1], [2, 3]]
Number of steps: 2

However, it has an infinite loop with nxn size(n>2) 但是,它有一个nxn大小的无限循环(n> 2)

Sample input: 样本输入:

int[][] initialState = { {7,2,4}, {5,0,6}, {8,3,1} };
int[][] goalState = { {0,1,2}, {3,4,5}, {6,7,8} };

It keeps adding nodes into the queue in DFS method 它不断在DFS方法中将节点添加到队列中

It makes me confused because the method checkTree in class Node has been written with the purpose to avoid loops which may happen when generate the states. 这让我感到困惑,因为类Node中的方法checkTree已被编写,目的是避免在生成状态时可能发生的循环。

Can somebody figure out what my mistake is? 有人能搞清楚我的错误是什么吗?

Late answer, but I hope it helps someone: 迟到的答案,但我希望它可以帮助某人:
The basic issue in the code posted are these lines : 发布的代码中的基本问题是这些行:

for(int i=0; i<row; i++){
    for(int j=0; j<col; j++){
        if ( matrix[i][j] == 0) {
           rowX = i;
           colX = j;
        }
    }
}

which result in checking "successor", or neighbors, only for the element (in state data) who`s value is 0. You need to check the neighbors of all elements. 这导致只检查值为0的元素(状态数据)中的“后继者”或邻居。您需要检查所有元素的邻居。 Note the comments in the code: 请注意代码中的注释:

import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Queue;
import java.util.Set;

public class Main {

    public static void BFS(Node root, Node goal) throws InterruptedException{
        Queue<Node> queue = new LinkedList<>();
        Set<Node> visited = new HashSet<>(); //**use to flow which nodes were tested
        queue.add(root);
        while(queue.size()>0){
            Node temp = queue.poll();
            if (temp.equals(goal)) {
                goal.setParent(temp.getParent());
                break;
            }
            else{
                List<Node> successor = temp.returnSuccessor();
                for(int i=0; i< successor.size(); i++){
                    //** made redundant by using visited boolean check = root.checkTree(successor.get(i));
                    Node node = successor.get(i);
                    if (visited.add(node)){ //** successful add indicates it was not visited before
                        queue.add(node);
                        temp.addChild(node);
                    }
                }
            }
        }
    }
    public static void main(String[] args) throws InterruptedException {

        int[][] initialState = { {0,1}, {2,3}, {4,5} };
        int[][] goalState = {{3,4}, {5,0}, {1,2}};

        Node root = new Node(new State(initialState));
        Node goal = new Node(new State(goalState));
        BFS(root,goal);

        if(goal.getParent() ==  null){
            System.out.println("There is no such a way to go from the initial state to the goal state");
        }
        else{
            ArrayList<Node> listSteps = new ArrayList<>();
            while(goal != null){
                listSteps.add(goal);
                goal = goal.getParent();
            }
            for (int i=listSteps.size()-1; i>=0; i--){
                System.out.println(listSteps.get(i));
            }
            int numSteps = listSteps.size()-1;
            System.out.println("Number of steps: " + numSteps);
        }
    }
}

class State {
    private int data[][];

    public int[][] getData() {  return data;}

    public void setData(int[][] data) { this.data = data;   }
    public void swap(int row1, int col1, int row2, int col2){
        int temp = data[row1][col1];
        data[row1][col1] = data[row2][col2];
        data[row2][col2] = temp;
    }

    public State copyState() { //**simpler version of
        int i = 0;
        int[][] temp = new int[data.length][];
        for (int[] row : data) {
            temp[i++] = Arrays.copyOf(row, row.length); //**simpler way to copy array
        }
        return new State(temp);
    }

    public State(int[][] data) {
        super();
        this.data = data;
    }
}

class Node {
    private State state;
    private Node parent;
    private ArrayList<Node> children;

    public Node(State state){
        this.state = state;
        parent = null;
        children = new ArrayList<>();
    }

    public State getState() {   return state; }
    public void setState(State state) { this.state = state; }
    public Node getParent() { return parent;}
    public void setParent(Node parent) { this.parent = parent;  }
    public ArrayList<Node> getChildren() {  return children;    }
    public void addChild(Node node){
        node.setParent(this);
        children.add(node);
    }

    public List<Node> returnSuccessor(){
        List<Node> result = new ArrayList<>();
        int[][] matrix = getState().getData();
        int row = matrix.length;
        int col = matrix[0].length;

        for(int i=0; i<row; i++){
            for(int j=0; j<col; j++){
                   /* need to check possible move for ALL nodes
                    * if ( matrix[i][j] == 0) {
                    rowX = i;
                    colX = j;
                   }*/

                    if( (j-1) >= 0 ){
                        State temp = getState().copyState();
                        temp.swap(i, j, i, j-1);
                        Node left = new Node(temp);
                        result.add(left);
                    }
                    if ( (j+1) < col ){
                        State temp = getState().copyState();
                        temp.swap(i, j, i, j+1);
                        Node right = new Node(temp);
                        result.add(right);
                    }
                    if ( (i-1) >= 0 ){
                        State temp = getState().copyState();
                        temp.swap(i, j, i-1, j);
                        Node top = new Node(temp);
                        result.add(top);
                    }
                    if ( (i+1) < row ){
                        State temp = getState().copyState();
                        temp.swap(i, j, i+1, j);
                        Node down = new Node(temp);
                        result.add(down);
                    }
            }
        }
        return result;
    }

    //override toString rather than creating
    @Override
    public String toString(){
        return Arrays.deepToString(getState().getData());
    }

    //**override equals rather than creating your own equal
    @Override
    public boolean equals(Object node){

           if (node == this) { return true; }
           if (node == null) { return false;}
           if (!(node instanceof Node)) {return false; }
        return Arrays.deepEquals(getState().getData(), ((Node)node).getState().getData());
    }

    //** override hashCode so each Node has a unique one
    @Override
    public int hashCode() {
        return toString().hashCode();
    }
}  

I also thing the terminology is a bit confusing. 我也认为术语有点令人困惑。 I think it would be cleared if every data element represented a Node, so int[][] initialState = { {2,1}, {3,0} }; 我认为如果每个数据元素都代表一个Node就会被清除,所以int[][] initialState = { {2,1}, {3,0} }; represented 4 nodes. 代表4个节点。 A collection of such nodes create a tree, which represents a unique State. 这些节点的集合创建了一个树,它代表一个唯一的状态。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM