BFS uninformed search issue

被刻印的时光 ゝ 提交于 2019-12-24 10:17:25

问题


I am trying to avoid an infinite loop and am having trouble figuring out whats wrong. This is supposed to find a solution for a 3x2 puzzle board. I suspect the problem may be with my overridden equals method but I'm not sure. Running into two issues:

1) It keeps re-exploring already explored nodes.

2) The queue is empty before a solution is found, causing an error.

Driver class:

import java.util.*;

public class Driver {

    public static void main(String[] args){
        Node test = new Node(new int[]{1, 4, 2, 5, 3, 0}, null);
        BFS(test);
        System.out.println("done");
    }

    public static void BFS(Node initial){
        Queue<Node> queue = new LinkedList<>();
        ArrayList<Node> explored = new ArrayList<>();
        queue.add(initial);
        Node current = initial;
        while (!current.isGoal()){
            current = queue.remove();
            for (Node child: current.getChildren()){
                if (!explored.contains(child)) queue.add(child);
            }
            explored.add(current);
            current.print();
        }

        System.out.println("DONEDONEDONE");
        current.printTrace();
    }

    public static void DFS(Node initial){

    }
}

Node class:

import java.lang.reflect.Array;
import java.util.*;

public class Node {
    int[] state;
    Node parent;

    public Node(int[] initialState, Node parent){
        this.parent = parent;
        this.state = initialState;
    }

    public boolean isGoal(){
        int[] goal = {0,1,2,3,4,5};
        return Arrays.equals(this.state, goal);
    }

    public ArrayList<Node> getChildren(){
        ArrayList<Node> children = new ArrayList<>();
        Integer[] newInt = new Integer[getState().length];
        for (int i = 0; i < getState().length; i++) {
            newInt[i] = Integer.valueOf(getState()[i]);
        }
        int position = Arrays.asList(newInt).indexOf(0);
        switch(position){
            case 0:
                children.add(new Node(switchPos(0,3), this));
                children.add(new Node(switchPos(0,1), this));
                break;
            case 1:
                children.add(new Node(switchPos(1,0), this));
                children.add(new Node(switchPos(1,4), this));
                children.add(new Node(switchPos(1,2), this));
                break;
            case 2:
                children.add(new Node(switchPos(2,1), this));
                children.add(new Node(switchPos(2,5), this));
                break;
            case 3:
                children.add(new Node(switchPos(3,0), this));
                children.add(new Node(switchPos(3,4), this));
                break;
            case 4:
                children.add(new Node(switchPos(4,3), this));
                children.add(new Node(switchPos(4,5), this));
                children.add(new Node(switchPos(4,1), this));
                break;
            case 5:
                children.add(new Node(switchPos(5,2), this));
                children.add(new Node(switchPos(5,4), this));
                break;

        }
        return children;
    }

    public int[] getState(){
        return this.state;
    }

    public int[] switchPos(int index1, int index2){
        int[] newer = getState().clone();
        int temp = newer[index1];
        newer[index1] = newer[index2];
        newer[index2] = temp;
        return newer;

    }

    public void print(){
        System.out.println("---------");
        System.out.println(Arrays.toString(Arrays.copyOfRange(getState(), 0, 3)));
        System.out.println(Arrays.toString(Arrays.copyOfRange(getState(), 3, 6)));
        System.out.println("---------");
    }

    public void printTrace(){
        Stack<Node> stack = new Stack<>();
        Node current = this;
        while (current.parent != null){
            stack.push(current);
            current = current.parent;
        }
        while (!stack.isEmpty()){
            stack.pop().print();
        }
    }

    @Override
    public boolean equals(Object object){
        Node node2 = (Node) object;
        return (Arrays.equals(node2.getState(), this.getState()));
    }
}

回答1:


The only real bug in your code is that you don't check if the queue is empty in the while condition, thus assuming that all states are available from any initial state (that's just not true).

I should also mention that marking the node as "explored" after the node is processed is not the best strategy, because duplicate nodes may be enqueued (from different parents), before any of them is processed. Note that they all will be printed as current, though all of their children are already processed -- and this may look like your algorithm is re-exploring the same nodes. In fact, it doesn't. It's just wasting cycles, that's all.

Here's a better version of the driver that doesn't allow duplicates in a queue:

Queue<Node> queue = new LinkedList<>();
ArrayList<Node> explored = new ArrayList<>();
queue.add(initial);
Node current = initial;
explored.add(initial);
while (!queue.isEmpty() && !current.isGoal()){
    current = queue.remove();
    for (Node child: current.getChildren()){
        if (!explored.contains(child)) {
            queue.add(child);
            explored.add(child);
        }
    }
    current.print();
}

Essential is that each node is marked as "explored" when it is first pushed to the queue. However, it still does not reach the "goal", because it is really unreachable from this particular initial state.



来源:https://stackoverflow.com/questions/48492428/bfs-uninformed-search-issue

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!