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

发布于 2024-08-17 07:52:07 字数 2858 浏览 2 评论 0 原文

我通过以下方式在加权有向图上实现 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....(到无穷大)。我的基于停靠次数或总行驶距离的条件可以终止此循环,但也会结束整个搜索,否则可以找到正确的路径,例如 ABCDCCDCD,当满足任一预设条件时,该搜索将正确终止。

感谢您的任何想法。

I am implementing DFS on a weighted directed graph in the following way:

    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+"]");
    }
}

I need to modify the above to allow cycles during the search for all paths between a source node and a destination node. To avoid infinite cycles, conditions can be set to terminate the search based on the number of "stops" made, or a maximum allowed distance traveled from the source.

This way I can find, for example, the number of trips starting at A and ending at D with exactly 5 stops: One solution can be ABCDCD. Or, I can find, say, the number of different routes from D to D with a distance of less than 40: a few solutions would be DECD, DEBCD, DCDCD.

My problem is that I am not sure how to create the logic of keeping the main algorithm searching, while escaping an infinite search cycle that is guaranteed not to reach the destination node.

Let's say I want to travel from A to D. A possible dead-end cycle can be ABCEBCEBCEB....(to infinity). My conditions based on number of stops, or total distance traveled, can terminate this loop, but will also end the entire search, which could otherwise find the right path of say ABCDCDCDCD, which will correctly terminate when either pre-set condition is met.

Thanks for any ideas.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

最舍不得你 2024-08-24 07:52:07

我认为您需要动态设置截止点/距离。例如,对于“A 到 D 正好 5 次停止”的问题,将截止值设置为 5 次停止将在达到 6 次停止时终止所有循环。如果将截止距离设置为 40,这同样适用于问题“D 到 D 的距离小于 40”。

可以使用“可达性矩阵”(即满足 a(如果存在从 i 到 j 的路径,则 i, j) = 1,否则 a(i, j) = 0。您可以通过首先查找图形的强连接组件来构建这样的矩阵(使用类似这个)。
然后,如果无法从当前节点访问目标节点,即 a(current, target) = 0,则可以拒绝搜索循环。

I think you need to set your cutoff stops/distance dynamically. For example, for a problem "A to D in exactly 5 stops", setting a cutoff value of 5 stops will terminate all cycles when they reach 6 stops. The same holds for the problem "D to D with a distance of less than 40", if you set a cutoff distance of 40.

Some cycles can be cut off earlier, using an "accessibility matrix", i.e. a matrix such that a(i, j) = 1 if there is a path from i to j or a(i, j) = 0 otherwise. You can construct such a matrix by first finding the strongly connected components of your graph (using an algorithm like this).
Then you can reject a search cycle, if the target node is not accessible from the current node, i.e. a(current, target) = 0.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文