简体   繁体   English

在 Prolog 中实现顶点覆盖

[英]Implementing vertex covering in Prolog

I am trying to implement vertex covering in prolog.我正在尝试在序言中实现顶点覆盖 I was thinking of doing following:我正在考虑做以下事情:

Use graph in following format [(VertexSouce/VertexDest), ...] and pass a number of total vertices in the graph.使用以下格式的图[(VertexSouce/VertexDest), ...]并传递图中的总顶点数。 So the predicate would look like this vertexCover(NodeCount, Graph, MaxNodesInResult, Result) .所以谓词看起来像这个vertexCover(NodeCount, Graph, MaxNodesInResult, Result) Result should be less than MaxNodesInResult` Result应该小于 MaxNodesInResult`

I was given following example output:我得到了以下示例输出:

?- vertexCover(6,[(1/2),(1/3),(2/3),(2/4),(3/5),(4/5),(4/6)],3,L).
L = [1,3,4] ;
L = [2,3,4] ;
false.
?- vertexCover(6,[(1/2),(1/3),(2/3),(2/4),(3/5),(4/5),(4/6)],2,L).
false.

Any help appreciated!任何帮助表示赞赏!

This should really be a comment on the correct solution by Dartuso, but it won't fit.这真的应该是 Dartuso 对正确解决方案的评论,但它不适合。 So here it is as an alternative answer.所以这里是一个替代答案。 Using Dartuso's code, you get duplicate answers:使用 Dartuso 的代码,您会得到重复的答案:

?- vertexCover(6,[(1/2),(1/3),(2/3),(2/4),(3/5),(4/5),(4/6)],3,L).
L = [1, 3, 4] ;
L = [1, 3, 4] ;
L = [2, 3, 4] ;
L = [2, 3, 4] ;
L = [2, 3, 4] ;
L = [2, 3, 4] ;
false.

There is nothing wrong with getting dupicate answers.得到重复的答案并没有错。 But sometimes we would like to avoid them for reasons of performance or simply to get nicer output.但有时我们出于性能原因或只是为了获得更好的输出而希望避免使用它们。

In this case the duplication comes from the fact that a single edge can occur in a cover in several ways:在这种情况下,重复来自这样一个事实,即单边可以以多种方式出现在封面中:

?- isIn([1, 3], (1/3)).
true ;
true ;
false.

This is because the clauses of isIn/2 as given by Dartuso are not mutually exclusive.这是因为 Dartuso 给出的isIn/2的子句并不相互排斥。 Both the first and the second clause match this query, which is why you get two successes.第一个和第二个子句都匹配此查询,这就是您获得两次成功的原因。

There are several ways to "fix" this.有几种方法可以“解决”这个问题。 The cleanest one is to add conditions to exclude cases already covered by previous clauses:最干净的方法是添加条件以排除前面条款已经涵盖的情况:

isIn([A|_],(X/_)) :-
    A = X.
isIn([A|_],(X/Y)) :-
    dif(A, X),
    A = Y.
isIn([A|T],(X/Y)) :-
    dif(A, X),
    dif(A, Y),
    isIn(T,(X/Y)).

Here the dif/2 predicate expresses disequality.这里的dif/2谓词表达了不平等。 So the second clause can no longer succeed in cases already covered by the equality in the first clause, and this eliminates the duplicate success and the duplicate answer:因此,第二个子句在第一个子句中的等式已经涵盖的情况下不再成功,这消除了重复的成功和重复的答案:

?- isIn([1, 3], (1/3)).
true ;
false.

?- vertexCover(6,[(1/2),(1/3),(2/3),(2/4),(3/5),(4/5),(4/6)],3,L).
L = [1, 3, 4] ;
L = [2, 3, 4] ;
false.

A somewhat less nice solution uses the "if-then-else" construct Condition -> TrueBranch ; FalseBranch一个不太好的解决方案使用“if-then-else”构造Condition -> TrueBranch ; FalseBranch Condition -> TrueBranch ; FalseBranch which is not unproblematic (but so very practical!): Condition -> TrueBranch ; FalseBranch并非没有问题(但非常实用!):

isIn([A|T],(X/Y)) :-
    (   A = X
    ->  true
    ;   A = Y
    ->  true
    ;   isIn(T, (X/Y)) ).

Or, as I might write this in practice:或者,正如我在实践中可能会写的那样:

isIn([A|T],(X/Y)) :-
    (   ( A = X ; A = Y )
    ->  true
    ;   isIn(T, (X/Y)) ).

With this latter solution the query above only succeeds once and doesn't even leave a choice point:使用后一种解决方案,上面的查询只成功一次,甚至没有留下选择点:

?- isIn([1, 3], (1/3)).
true.

And with this the overall predicate no longer has duplicate answers either:有了这个,整体谓词也不再有重复的答案:

?- vertexCover(6,[(1/2),(1/3),(2/3),(2/4),(3/5),(4/5),(4/6)],3,L).
L = [1, 3, 4] ;
L = [2, 3, 4] ;
false.

In this particular case the if-then-else only cuts away unwanted duplicate solutions, but in general it can eliminate solutions you did want.在这种特殊情况下,if-then-else 只会删除不需要的重复解决方案,但通常它可以消除您想要的解决方案。 Use with care.小心使用。

(Others might tell you to use the cut operator !/0 because it's shorter than some of these solutions. Do not give in. Shorter code is not automatically better code, and the cut makes your code especially complicated and hard to understand and to modify.) (其他人可能会告诉您使用剪切运算符!/0因为它比这些解决方案中的一些更短。不要屈服。较短的代码并不是自动更好的代码,并且剪切会使您的代码特别复杂且难以理解和修改.)

Here is a working solution, thanks to Isabelle for the fix!这是一个有效的解决方案,感谢 Isabelle 的修复! As she mentioned another solution I found was to add a cut on the second line of covers/2 but her solution is much more clear.正如她提到的,我发现的另一个解决方案是在covers/2的第二行添加一个切口,但她的解决方案更加清晰。

vertexCover(N,L1,M,L2) :- numlist(1, N, L), comb(M,L,L2), covers(L2,L1).

covers(_,[]).
covers(L,[H|T]) :- isIn(L,H), covers(L,T).

isIn([A|T],(X/Y)) :-  (( A = X ; A = Y ) -> true
                       ;   isIn(T, (X/Y)) ).

comb(0,_,[]).
comb(N,[X|T],[X|Comb]):-    N>0,N1 is N-1,comb(N1,T,Comb).
comb(N,[_|T],Comb):-        N>0,comb(N,T,Comb).

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM