prolog图深度优先搜索

时间:2018-06-08 18:33:32

标签: graph prolog depth-first-search

我已经看过有关深度优先搜索的其他问题,但我的问题略有不同,我真的不明白。 在prolog中,我代表我的无向图:

HBox

这是一组键值,其中键表示节点和列表:import javafx.application.Application; import javafx.geometry.Insets; import javafx.geometry.Pos; import javafx.scene.Scene; import javafx.scene.control.Button; import javafx.scene.control.TextField; import javafx.scene.layout.HBox; import javafx.scene.layout.VBox; import javafx.stage.Stage; public class Main extends Application { private static VBox mainPane; public static void main(String[] args) { launch(args); } @Override public void start(Stage primaryStage) { mainPane = new VBox(5); mainPane.setPadding(new Insets(10)); mainPane.setAlignment(Pos.TOP_CENTER); mainPane.getChildren().add(new UIForms()); primaryStage.setScene(new Scene(mainPane)); primaryStage.show(); } static void addField() { mainPane.getChildren().add(new UIForms()); } static void removeField(UIForms field) { if (mainPane.getChildren().size() > 1) { mainPane.getChildren().remove(field); } } } class UIForms extends HBox { private TextField textField1; private TextField textField2; private Button btnAddField; private Button btnRemoveField; public UIForms() { // Setup the HBox layout setAlignment(Pos.CENTER_LEFT); setSpacing(5); // Create the UI controls textField1 = new TextField(); textField2 = new TextField(); btnAddField = new Button("+"); btnRemoveField = new Button("-"); // Setup button actions btnAddField.setOnAction(e -> Main.addField()); btnRemoveField.setOnAction(e -> Main.removeField(this)); // Add the UI controls getChildren().addAll( textField1, textField2, btnAddField, btnRemoveField ); } } 表示其邻居。

我不知道如何使用此模型进行深度优先搜索。我尝试了很多解决方案。我想要一个非常基本的递归算法,如下所示:

[0-[1,5], 1-[0,2], 2-[1,3], 3-[2,0], 5-[0]]

我无法在prolog中做的是作为可变引用访问的传递,它将被每个邻居递归修改为下一个邻居。

因为如果我把它翻译成prolog:

-[]

我需要某种折叠,每个邻居都会调用dfs并将其结果传递给下一个邻居,但我不知道如何做到这一点......

感谢。

2 个答案:

答案 0 :(得分:1)

直接将您的代码翻译成Prolog。不要过分思考它;说出你的意思:

/* dfs(v, visited):
     if visited[v] then return
     visited.insert(v)
     foreach neighbor of v:
       dfs(neighbor, visited) */

dfs(Graph, V, Visited, Return) :-
   visited(V, Visited),
   return(Graph, V, Visited, Return).

dfs(Graph, V, Visited, Return) :-
   \+ visited(V, Visited),
   appended(Visited, [V], Visited2),
   neighbor(Graph, V, N),
   dfs(Graph, N, Visited2).

谓词visited/2return/4appended/3neighbor/3应该很容易实现。

首先是正确性,以后是效率。

答案 1 :(得分:0)

传统的DFS算法涉及递归和堆栈,它基本上是一种回溯机制。在Prolog中,如果你想要积累"如果您需要的元素是在回溯中获得的,那么列表可能具有挑战性。

以下代码是DFS搜索的非常简单的呈现,并将在DFS搜索中写出节点:

dfs(Graph, StartNode) :-
    dfs(Graph, StartNode, []).

dfs(Graph, Node, Visited) :-
    \+ member(Node, Visited),
    member(Node-Neighbors, Graph),
    write(Node), nl,
    member(NextNode, Neighbors),
    dfs(Graph, NextNode, [Node|Visited]).

两个member调用看起来有点像你试图做的那样,但不完全一样。它们共同构成了这种结构的DFS遍历的关键。

查询这个你会得到:

| ?- dfs([0-[1,5], 1-[0,2], 2-[1,3], 3-[2,0], 5-[0]], 0).
0
1
2
3
5

yes
| ?-

但是,写出图中的节点并不是特别有用。我们想在列表中收集它们。可以修改上述内容,使其成为沿搜索路径成功的每个节点的谓词。

dfs(Graph, StartNode, Node) :-
    dfs(Graph, StartNode, [], Node).

dfs(Graph, ThisNode, Visited, Node) :-
    \+  member(ThisNode, Visited),
    (   Node = ThisNode                     % Succeed finding a new node
    ;   member(ThisNode-Neighbors, Graph),  % Or... find the next node
        member(NextNode, Neighbors),
        dfs(Graph, NextNode, [ThisNode|Visited], Node)
    ).

这导致:

| ?- dfs([0-[1,5], 1-[0,2], 2-[1,3], 3-[2,0], 5-[0]], 0, Node).

Node = 0 ? a

Node = 1

Node = 2

Node = 3

Node = 5

no
| ?-

现在您可以使用findall/3将节点作为列表获取:

dfs_path(Graph, StartNode, Nodes) :-
    findall(Node, dfs(Graph, StartNode, Node), Nodes).

现在你可以写:

| ?- dfs_path([0-[1,5], 1-[0,2], 2-[1,3], 3-[2,0], 5-[0]], 0, Nodes).

Nodes = [0,1,2,3,5]

yes
| ?-