2

無向グラフとして表されるこの迷路があります。これがどのように見えるかです:

11 3
2 3
0 3
1 4
5 4
5 7
6 7
7 8
8 9
9 10
6 11
7 11

このグラフでは、深さ優先検索を使用して、開始ノードから目標ノードまでのソリューションを示しています。開始ノードとしての入力は0で、目標ノードは1です。目標への道として私が得た解決策は です0-3-11-7-5-4-1が、もう一度分析すると である別の解決策もあり0-3-11-6-7-5-4-1ます。ここでの私の目的は、最良の解を示すことではなく、それらの解がいくつあるかを示し、後で最良の解を分析することです。

私が抱えている問題は、複数のソリューションを印刷できないことです。0-3-11-7-5-4-1他には何も印刷されず0-3-11-6-7-5-4-1、印刷されるものが2つあると予想されるため、これが表示されることもあります。これまでに行ったコードは次のとおりです。

public class DepthFirstSearch {

    private final boolean[] visited;
    private final int sourceNode;
    private final int[] pathTo;

    /**
     *
     * @param mazeGraph
     * @param sourceNode
     * @param goal
     */
    public DepthFirstSearch(MazeGraph mazeGraph, int sourceNode, int goal) {
        this.sourceNode = sourceNode;
        visited = new boolean[mazeGraph.node];
        pathTo = new int[mazeGraph.node];
        performRecursiveDFS(mazeGraph, sourceNode, goal);
    }

    //Perform recursive depth-first search
    private void performRecursiveDFS(MazeGraph mazeGraph, int node, int goal) {
        visited[node] = true;
        for (int arc : mazeGraph.getAdjacencyList(node)) {
            if (!visited[arc]) {

                pathTo[arc] = node;
                performRecursiveDFS(mazeGraph, arc, goal);

            }
        }
    }

    //Put path to goal in the stack
    public Stack<Integer> pathTo(int toGoalNode) {
        if (!visited[toGoalNode]) {
            return null;
        }
        Stack<Integer> pathStack = new Stack<Integer>();
        for (int pathToGoalNode = toGoalNode; pathToGoalNode != sourceNode; pathToGoalNode = pathTo[pathToGoalNode]) {
            pathStack.push(pathToGoalNode);
        }
        pathStack.push(sourceNode);
        reverseStack(pathStack);
        return pathStack;
    }

    //Reverse the stack
    public void reverseStack(Stack<Integer> stackToBeReverse) {

        if (stackToBeReverse.isEmpty()) {
            return;
        }

        int bottom = popBottomStack(stackToBeReverse);
        reverseStack(stackToBeReverse);
        stackToBeReverse.push(bottom);
    }

    //Pop the bottom of the stack
    private int popBottomStack(Stack<Integer> stackToBeReverse) {
        int popTopStack = stackToBeReverse.pop();
        if (stackToBeReverse.isEmpty()) {
            return popTopStack;
        } else {
            int bottomStack = popBottomStack(stackToBeReverse);
            stackToBeReverse.push(popTopStack);
            return bottomStack;
        }
    }

    //Print the path to goal
    public void printPath( int toGoal) {

        if (visited[toGoal]) {
            out.println("Path to Goal: ");
            for (int x : pathTo(toGoal)) {
                if (x == toGoal) {
                    out.print(x);
                } else {
                    out.print(x + " - ");
                }
            }
            out.println();
        }
    }

    /**
     *
     * @param args
     */
    public static void main(String[] args) {
        Scanner scanFile = new Scanner(in);
        out.print("Enter maze file: ");
        String file = scanFile.nextLine();
        out.print("Enter start node: ");
        int startNode = scanFile.nextInt();
        out.print("Enter goal node: ");
        int goalNode = scanFile.nextInt();
        MazeGraph mazeGraph = new MazeGraph(file);
        mazeGraph.print();
        out.println("Starting at 0\nGoal at 1");           
        DepthFirstSearch depthFirstSearch = new DepthFirstSearch(mazeGraph, startNode, goalNode);
        depthFirstSearch.printPath( goalNode);
        }

}

メイズグラフのソースコード:

public class MazeGraph {

    final int node; //Declaring constant value of a node.
    int arc;
    List<Integer>[] adjacencyList;
    final static Set<Integer> setOfNodes = new HashSet<Integer>();

    /**
     * This constructors takes an integer parameter for reading node indexes in
     * a list of adjacent nodes.
     *
     * @param node - integer parameter for passing the nodes value from the file
     * and create a list of adjacent nodes.
     */
    MazeGraph(int node) {
        this.node = node;
        this.arc = 0;
        adjacencyList = (List<Integer>[]) new List[node];
        for (int index = 0; index < node; index++) {
            adjacencyList[index] = new LinkedList<Integer>();
        }
    }

    /**
     * The main constructor that takes a String for reading maze file.
     *
     * @param mazeFile
     */
    public MazeGraph(String mazeFile) {
        this(getNodeSize(mazeFile));
        Scanner scan;
        try {
            //Scan maze file.
            scan = new Scanner(new File(mazeFile));

            /*loop when it has next integer then read two nodes from the file and add arc for it.*/
            while (scan.hasNextInt()) {
                int node1 = scan.nextInt();
                int node2 = scan.nextInt();
                addArc(node1, node2);
            }
        } catch (FileNotFoundException ex) {
            out.println("File not found.");
        }
    }

    /**
     * This method returns a size of the set of nodes by taking a String
     * parameter which the name of the maze file.
     *
     * @param mazeFile - String parameter for reading maze file for scanning the
     * size of the nodes.
     * @return - returns an integer value for the size of the set of nodes.
     */
    public static int getNodeSize(String mazeFile) {
        Scanner scanNodeSize;
        try {
            scanNodeSize = new Scanner(new File(mazeFile));
            while (scanNodeSize.hasNextInt()) {
                int node1 = scanNodeSize.nextInt();
                int node2 = scanNodeSize.nextInt();
                setOfNodes.add(node1);
                setOfNodes.add(node2);
            }
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        }
        return setOfNodes.size();
    }

    /**
     * This method adds an arc by adding two different nodes in array of list
     * called adjacency list.
     *
     * @param node1 - first node.
     * @param node2 - next node.
     */
    private void addArc(int node1, int node2) {
        arc++; //Increase arc by one whenever this addArc method is called.
        adjacencyList[node1].add(node2);
        adjacencyList[node2].add(node1);
    }

    /**
     * Print the nodes and its arcs by looping through the adjacency list.
     */
    public void print() {
        out.println(node + " Nodes, " + arc + " Arcs \n");
        for (int n = 0; n < node; n++) {
            out.print(n + " connected to ");
            for (int w : adjacencyList[n]) {
                out.print(w + " ");
            }
            out.println();
        }
    }

    /**
     * This method returns a list of nodes to allow objects to be the target for
     * "for-each" statement.
     *
     * @param nodes - an Integer parameter for getting the number of nodes in a
     * list.
     * @return - returns a list of nodes.
     */
    public Iterable<Integer> getAdjacencyList(int nodes) {
        return adjacencyList[nodes];
    }

    /**
     * Unit testing To test if it reads the file.
     *
     * @param args
     */
    public static void main(String[] args) {
        out.print("Enter maze file: ");
        Scanner scanFile = new Scanner(in);
        String file = scanFile.nextLine();
        MazeGraph G = new MazeGraph(file);
        G.print();
    }

}

なぜこれが起こっているのかを詳細に説明し、これを改善する方法について提案/アドバイスをください. コードの品質も確認してください。問題がなければ、確認しなくてもかまいません。とにかく事前に感謝します。

4

1 に答える 1

2

アルゴリズムには大きな欠陥があるため、実際には幸運ですvisited。再帰呼び出しを終了しても設定を解除しません。したがって、これをに追加する必要がありますperformRecursiveDFS

private void performRecursiveDFS(MazeGraph mazeGraph, int node, int goal) {
    visited[node] = true; //set visited
    for (int arc : mazeGraph.getAdjacencyList(node)) {
        if (!visited[arc]) {
            pathTo[arc] = node;
            performRecursiveDFS(mazeGraph, arc, goal);

        }
    }
    visited[node] = false; //unset visited
}

これが必要なのは、「バックトラック」して別のパスを探しており、そのパスをnodeまだ訪れていないためです。

さらに、再帰呼び出しでは、目標に到達したかどうかを検査し、到達した場合はパスを出力できます。

private void performRecursiveDFS(MazeGraph mazeGraph, int node, int goal) {
    visited[node] = true; //set visited
    if(node == goal) { //found the goal? Good, print it and backtrack.
        printPath(goal);
    } else {
        for (int arc : mazeGraph.getAdjacencyList(node)) {
            if (!visited[arc]) {
                pathTo[arc] = node;
                performRecursiveDFS(mazeGraph, arc, goal);
            }
        }
    }
    visited[node] = false; //unset visited
}

もちろん、パスを表示する以外のこともできます。たとえば、カウントしたり、パスをリストに保存したりできます。

編集:あなたが提供した迷路ファイルでそれをテストしました、私は得ます:

$ java DepthFirstSearch
Enter maze file: maze
Enter start node: 0
Enter goal node: 1
12 Nodes, 12 Arcs 

0 connected to 3 
1 connected to 4 
2 connected to 3 
3 connected to 11 2 0 
4 connected to 1 5 
5 connected to 4 7 
6 connected to 7 11 
7 connected to 5 6 8 11 
8 connected to 7 9 
9 connected to 8 10 
10 connected to 9 
11 connected to 3 6 7 
Starting at 0
Goal at 1
Path to Goal: 
0 - 3 - 11 - 6 - 7 - 5 - 4 - 1
Path to Goal: 
0 - 3 - 11 - 7 - 5 - 4 - 1
于 2015-12-26T22:06:01.253 に答える