我试图通过解决Advent Of Code谜题来学习Prolog,并且最终被困在我认为应该非常简单的任务上。有疑问的是this one。该任务要求我找到连接到程序ID 0的所有程序ID(整数)。连接是对称的和可传递的,因此如果来自不同连接组的程序之间存在连接,则给定组中的所有程序都相互连接。
我目前的情况是,我将拼图中的整数分类为子列表,每个子列表代表他们所属的组。
例如:[[0, 2], [1, 1], [2, 0, 3, 4], [3, 2, 4], [4, 2, 3, 6], [5, 6], [6, 4, 5]]
我需要获得所有以某种方式连接到0的程序。在这个例子中,除了ID为1的程序之外,这将是所有程序。
因此,我正在寻找的逻辑是设法检查包含0的扩展组和我的递归谓词连接当前正在查看的组中是否存在给定整数的东西。我意识到这种方法可能最终忽略了在递归中早先看到的组的新连接,但这是一个单独的问题。
将程序排序到上面的子列表中不是问题,因此我将此部分省略到目前为止。
main(R) :-
Groups = [[0, 2], [1, 1], [2, 0, 3, 4], [3, 2, 4], [4, 2, 3, 6], [5, 6], [6, 4, 5]],
connected(Groups, [0], R).
connected([H|T], X, R) :-
member(Y, H), member(Y, X) -> flatten([H|X], X1), connected(T, X1, R) ; R = X.
我来到这里的结果很简单:[0,2,0]
我期望的结果是:[0,2,0,2,0,3,4,3,2,4,4,2,3,6,5,6,6,4,5]
我已经意识到元素[1,1]
可能会过早地停止递归,所以我尝试将上面的最后一行更改为以下内容:
member(Y, H), member(Y, X) -> flatten([H|X], X1), connected(T, X1, R) ; connected(T, X, R).
然而,这只会导致主(R)。由于某种原因评估为假。同样,如果我只是从组中删除[1,1]
而不更改最后一行,则返回false。
我认为我忽略了一些非常简单的事情,并且会欣赏任何输入。
答案 0 :(得分:2)
假设您的群组具有正确的结构,您可以保留一个“未访问”群组的列表,并在每个递归步骤中采用未访问的项目并添加其仍然未访问的邻居。
即:
main(R) :-
Groups = [[0, 2], [1, 1], [2, 0, 3, 4], [3, 2, 4], [4, 2, 3, 6], [5, 6], [6, 4, 5]],
connected([0], [], Groups, R).
connected([], _, _, []).
connected([P|Tail], Visited, Groups, [P|R]):-
select([P|Ps], Groups, NGroups), % Get the item's neighours
subtract(Ps, [P|Visited], NPs), % subtract from it the visited ones
union(Tail, NPs, NTail), % and add these neighours to the unvisited list
connected(NTail, [P|Visited], NGroups, R).
这将获得一组没有重复的“连接”程序:
?- main(R).
R = [0, 2, 3, 4, 6, 5]