我需要编写一个谓词,使用Prim's Algorithm创建加权无向图的最小生成树。这就是我到目前为止所做的:
% call the recursive predicate with the list of all nodes and
% one element (in this case the last one).
mst(T) :- nodes(N), last(N,E), mst(T,N,E).
% The element E is added to the visited list and removed from the toVisit list.
mst(T,N,E) :- append(T,E,S), delete(R,E,L)...
然后,toVisit
列表应根据连接到访问列表中任何节点的边的距离进行排序。有关如何做到这一点的任何建议吗?
答案 0 :(得分:0)
因此,首先让我们尝试创建一个解决方案,以便从维基百科中找到生成树而不是最小值:“无向图的生成树T
G
是一个树的子图其中包括G
的所有顶点,边数最小可能“和”树是一个没有周期的连通无向图。如果它跨越G
,它就是图G
的生成树{ {1}}(也就是说,它包含G
的每个顶点)并且是G
的子图(树中的每个边都属于G
)“。在这个例子中,我考虑以这种方式构建的图形:
graph(ListOfVertices,ListOfEdges)
并且ListOfEdges的每个元素都是edge(X,Y,Cost)
。
让我们构建一个创建树的谓词(在本例中是一个完全连接的图)。 make_kn_weighted/4
输入每个节点的度数(Size
),边缘费用的MinValue
和MaxValue
,并在graph(LV,Comb)
中创建图表。
make_kn_weighted(Size,MinValue,MaxValue,graph(LV,Comb)):-
Size1 is Size+1,
make_ordered_list(1,Size1,LV),
find_all_combinations_weighted(LV,MinValue,MaxValue,[],Comb).
make_ordered_list(Max,Max,[]):- !.
make_ordered_list(I,Max,[I|T]):-
I < Max,
I1 is I+1,
make_ordered_list(I1,Max,T).
find_all_combinations_weighted([_],_,_,C,C):- !.
find_all_combinations_weighted([H|T],Min,Max,CT,CO):-
find_combinations_weighted(H,T,Min,Max,C),
append(CT,C,C1),
find_all_combinations_weighted(T,Min,Max,C1,CO).
find_combinations_weighted(_,[],_,_,[]):- !.
find_combinations_weighted(E,[H|T],Min,Max,[edge(E,H,V)|TE]):-
random(Min,Max,V),
find_combinations_weighted(E,T,Min,Max,TE).
?- make_kn_weighted(4,2,7,G).
G = graph([1, 2, 3, 4], [edge(1, 2, 6), edge(1, 3, 6), edge(1, 4, 5), edge(2, 3, 4), edge(2, 4, 5), edge(3, 4, 5)]).
然后我们创建一个生成生成树的谓词:
spanning_tree(graph([N|T],Edges),graph([N|T],TreeEdges)) :-
generate_spanning_tree(T,Edges,TreeEdgesUnsorted),
sort(TreeEdgesUnsorted,TreeEdges).
generate_spanning_tree([],_,[]).
generate_spanning_tree(Curr,Edges,[Edge|T]) :-
select(Edge,Edges,Edges1),
get_vertices(Edge,X,Y),
is_connected_to_tree(X,Y,Curr),
delete(Curr,X,Curr1),
delete(Curr1,Y,Curr2),
generate_spanning_tree(Curr2,Edges1,T).
get_vertices(edge(X,Y),X,Y).
get_vertices(edge(X,Y,_),X,Y).
is_connected_to_tree(X,Y,Ns):-
memberchk(X,Ns),
\+ memberchk(Y,Ns), !.
is_connected_to_tree(X,Y,Ns):-
memberchk(Y,Ns),
\+ memberchk(X,Ns).
所以,显然,生成树和图形都有相同的顶点,这就是我写graph([N|T],Edges),graph([N|T],TreeEdges)
的原因。为了生成实际树,我们从列表中选择一个节点select/3
(在Edges1
中,我们拥有Edges
中没有Edge
的所有元素。然后使用{{我们用边缘连接两个顶点。用get_vertices/3
我们检查两个顶点是否已经连接(在列表中或剩下的副本中)。然后我们将两个选定的边删除到未连接的列表中顶点(is_connected_to_tree/3
)使用两次Curr
应用于delete/3
。最后一次调用,参数更新的递归调用。测试:
Curr
现在让我们关注Primm的算法:为了调整我们的谓词以最低成本生成树,我们首先考虑每条边的成本对边进行排序,然后我们可以调用,如上所述{{1} }。所以,在prolog代码中:
?- make_kn(4,G), spanning_tree(G,T).
G = graph([1, 2, 3, 4], [edge(1, 2), edge(1, 3), edge(1, 4), edge(2, 3), edge(2, 4), edge(3, 4)]),
T = graph([1, 2, 3, 4], [edge(1, 2), edge(1, 3), edge(1, 4)]) ;
G = graph([1, 2, 3, 4], [edge(1, 2), edge(1, 3), edge(1, 4), edge(2, 3), edge(2, 4), edge(3, 4)]),
T = graph([1, 2, 3, 4], [edge(1, 2), edge(1, 3), edge(2, 4)])
and so on...
generate_spanning_tree/3
使用mst_prim(graph([H|T],Edges),graph([H|T],TreeEdges),Cost):-
predsort(compare_edges_value,Edges,SortedEdges),
generate_spanning_tree(T,SortedEdges,TreeEdgesUnsorted),
sort(TreeEdgesUnsorted,TreeEdges),
sum_cost(TreeEdges,0,Cost).
compare_edges_value(O,edge(X1,Y1,C1),edge(X2,Y2,C2)):-
compare(O,C1+X1+Y1,C2+X2+Y2).
sum_cost([],C,C).
sum_cost([edge(_,_,C)|T],CT,Tot):-
CT1 is CT+C,
sum_cost(T,CT1,Tot).
进行排序以确定订单。 predsort/3
只是总结每个选定边的成本。查询:
compare_edge/3
在回溯中,它会生成所有生成树(如果您不想要此行为,则可以在调用sum_cost/3
后添加剪切)。