【问题标题】:Prolog: how to get all the combinationsProlog:如何获得所有组合
【发布时间】:2014-12-12 23:21:26
【问题描述】:

我有以下例子:

bag(b1)
bag(b2)

item(i1)
item(i2)
item(i3)
item(i4)

现在我真的不明白如何才能从中获得所有可能性?我必须使用所有的包。 就像我应该得到这样的列表列表:

[ [together(b1, [i1,i2,i3,i4]), together(b2, [])] ,..., [together(b1, [i1]), together(b2, [i2,i3,i4])] [together(b1, [i1,i2]), together(b2, [i3,i4])] ]

等所有可能的组合但它必须使用所有项目。我知道我可以使用findall 获取事实,但后来我被卡住了

这就是我所拥有的:

test(X) :-
findall(C, bag(C),Bags),
findall(K, item(K),Items),
something???

关于从哪里开始的任何想法,因为我一无所知,我不明白如何思考才能达到这样的结果。

获得组合的可能想法:

item_combination(C) :-
    findall(I, item(I), Is),
    combination(Is, C).

combination(_, []).
combination(Set, [X|Xs]) :-
    select(X, Set, Set0),
    combination(Set0, Xs).

我需要类似的东西,获取第一个袋子的组合,然后转到下一个袋子,取一个组合,如果它有效(所有使用的项目)附加到列表中,否则返回第一个袋子与其他组合等等......还是有更好的解决方案?

提前致谢!

【问题讨论】:

    标签: prolog combinations


    【解决方案1】:

    您首先定义一个谓词powset/3,该谓词从给定集合中生成所有幂集,并将未选择元素作为第三个列表:

    powset3([],[],[]).
    powset3([H|T],T2,[H|T3]) :-
        powset3(T,T2,T3).
    powset3([H|T],[H|T2],T3) :-
        powset3(T,T2,T3).
    

    接下来,我们定义一个divide/3 命令,它给定一个项目列表,将其除以N 集合:

    divide(_,N,[]) :-
        N < 1.
    divide(Items,1,[Items]).
    divide(Items,N,[Selected|Other]) :-
        N > 1,
        powset3(Items,Selected,Rest),
        N1 is N-1,
        divide(Rest,N1,Other).
    

    最后是一个ziptogether/3 实用程序,它将两个列表压缩成一个谓词列表:

    ziptogether([],[],[]).
    ziptogether([HA|TA],[HB|TB],[together(HA,HB)|TC]) :-
        ziptogether(TA,TB,TC).
    

    你可以这样做:

    findall(I,item(I),Is),
    findall(B,bag(B),Bs),
    length(Bs,NB),
    findall(Proposal,(divide(Is,NB,Ds),ziptogether(Bs,Ds,Proposal)),List).
    

    示例:

    ?- findall(I,item(I),Is),
    |        findall(B,bag(B),Bs),
    |        length(Bs,NB),
    |        findall(Proposal,(divide(Is,NB,Ds),ziptogether(Bs,Ds,Proposal)),List).
    Is = [i1, i2, i3, i4],
    Bs = [b1, b2],
    NB = 2,
    List = [[together(b1, []), together(b2, [i1, i2, i3, i4])], [together(b1, [i4]), together(b2, [i1, i2, i3])], [together(b1, [i3]), together(b2, [i1, i2, i4])], [together(b1, [i3, i4]), together(b2, [i1, i2])], [together(b1, [i2]), together(b2, [i1|...])], [together(b1, [i2|...]), together(b2, [...|...])], [together(b1, [...|...]), together(..., ...)], [together(..., ...)|...], [...|...]|...].
    

    懒人版

    使用findall 的先前版本是活动的:它会生成整个配置列表。在许多情况下,惰性评估更好:它可以生成有限数量的实例。懒惰的版本是:

    getBagConfig(Proposal) :-
        findall(I,item(I),Is),
        findall(B,bag(B),Bs),
        length(Bs,NB),
        divide(Is,NB,Ds),
        ziptogether(Bs,Ds,Proposal).
    

    时间复杂度: 算法在 O(b^n+b+n) 中运行,其中 b 为箱数,n 为箱数,n 为项目数。

    注意: 很可能一些引入的谓词已经存在于很多Prolog实现中,但是由于这些谓词没有标准化,最好自己提供一个实现。

    【讨论】:

    • 新版本使用powersets,这是预期的程序吗?
    • 哈哈,不,你可能想把物品放在三个袋子上,比如0-1多背包问题?
    • 是的,它必须使用所有项目,(我在问题中给出了一个解决方案的示例),是的,类似于背包问题,但我只是不明白你的想法解决它:)
    • 这似乎是正确的.. :) 我会检查一下,谢谢
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2017-05-04
    • 1970-01-01
    • 1970-01-01
    • 2018-05-08
    • 1970-01-01
    • 1970-01-01
    • 2012-11-25
    相关资源
    最近更新 更多