在DFS期间重新访问节点并控制无限循环

时间:2010-01-03 20:16:44

标签: java graph cycle depth-first-search

我正在通过以下方式在加权有向图上实现DFS:

    public class DFSonWeightedDirectedGraph {

    private static final String START = "A";
    private static final String END = "C";
    private int pathLength = 0;
    private int stops = 0;

    public static void main(String[] args) {
        //this is a directed weighted graph
        WeightedDirectedGraph graph = new WeightedDirectedGraph();
        graph.addEdge("A", "B", 5);
        graph.addEdge("A", "D", 5);
        graph.addEdge("A", "E", 7);
        graph.addEdge("B", "C", 4);
        graph.addEdge("C", "D", 8);
        graph.addEdge("C", "E", 2);
        graph.addEdge("D", "C", 8);
        graph.addEdge("D", "E", 6);
        graph.addEdge("E", "B", 3);

        LinkedList<String> visited = new LinkedList<String>();
        visited.add(START);
        new DFSonWeightedDirectedGraph().depthFirst(graph, visited);
    }

    private void depthFirst(WeightedDirectedGraph graph, LinkedList<String> visited) {
        Collection<Map.Entry<String, Integer>> nodes = graph.adjacentNodes(visited.getLast());      
        // examine adjacent nodes
        for (Map.Entry<String, Integer> node : nodes) {
            if (visited.contains(node.getKey())) {
                continue;
            }
            if (node.getKey().equals(END)) {
                visited.addLast(node.getKey());  
                pathLength += node.getValue();
                stops += 1;
                printPath(visited);
                visited.removeLast();
                pathLength -= node.getValue();
                stops -= 1;
                break;
            }
        }
        // recursion
        for (Map.Entry<String, Integer> node : nodes) {
            if (visited.contains(node.getKey()) || node.getKey().equals(END)) {
                continue;
            }
            visited.addLast(node.getKey());
            pathLength += node.getValue();
            stops += 1;
            depthFirst(graph, visited);
            visited.removeLast();
            pathLength -= node.getValue();
            stops -= 1;
        }
    }

    private void printPath(LinkedList<String> visited) {
        for (String node : visited) {
            System.out.print(node);
            System.out.print(" ");
        }
        System.out.println("[path length: "+pathLength +
                " stops made: "+ stops+"]");
    }
}

我需要修改上面的内容,以便在搜索源节点和目标节点之间的所有路径时允许循环。为了避免无限循环,可以设置条件以根据所做的“停止”次数或从源传播的最大允许距离来终止搜索。

通过这种方式,我可以找到例如从A开始到D结束的行程数,恰好有5个停靠点:一个解决方案可以是ABCDCD。或者,我可以找到从D到D的距离小于40的不同路线的数量:一些解决方案是DECD,DEBCD,DCDCD。

我的问题是我不确定如何创建保持主算法搜索的逻辑,同时避免无限的搜索周期,保证不会到达目标节点。

假设我想从A到D旅行。可能的死胡同周期可以是ABCEBCEBCEB ....(到无限远)。我基于停靠次数或总行进距离的条件可以终止此循环,但也将结束整个搜索,否则可能找到正确的ABCDCDCDCD路径,当满足任一预设条件时,该路径将正确终止。

感谢任何想法。

1 个答案:

答案 0 :(得分:1)

我认为您需要动态设置截止停止/距离。例如,对于“正好5档中的A到D”的问题,设置5档的截止值将在它们达到6档时终止所有循环。如果将截止距离设置为40,则问题“D到D的距离小于40”也是如此。

使用“可访问性矩阵”可以更早地切断某些周期,即如果存在从i到j或a(i,j)= 0的路径,则a(i,j)= 1的矩阵。您可以通过首先找到图表中的强连接组件来构建此类矩阵(使用this之类的算法)。
如果目标节点无法从当前节点访问,即(当前,目标)= 0,则可以拒绝搜索周期。