使用Prolog解决难题,抛出错误“参数未充分实例化”

时间:2016-04-04 15:44:37

标签: prolog clpfd

我正在尝试使用逻辑约束来解决以下问题:

  

封隔器必须将5个板条箱放在长货车上。 5个板条箱   含有鸡,大麦,狐狸,鼠毒和小麦。板条箱需要   排成一行,没有任何间隙,以便:

     

•鸡与狐狸分开;

     

•鼠药不在大麦旁边;

     

•鼠药不在小麦旁边。

     

找出答案   怎么可能有不同的安排这些板条箱的方式   这些包装限制。

这是我到目前为止所做的:

:- use_module(library(clpfd)).

position(Crates) :-
   Crates = [Chicken, Barley, Foxes, RatPoison, Wheat],
   Regions ins 1..5,
   Chicken   #\= Foxes,
   RatPoison #\= Barley,
   RatPoison #\= Wheat,
   labeling([], Regions).

当我尝试运行它时会抛出错误“参数没有充分实例化”。

我对Prolog很新,所以任何帮助都会受到赞赏。

2 个答案:

答案 0 :(得分:2)

Firstly you are restricting Regions to 1..5 and than labeling it. But you want to know the possible positions for the 5 crates. So restrict and label Crates. Note that Regions is a free variable when you restrict it to values between 1 and 5 and the length of the list Regions is not restricted at all, thus the error when you try to label it. In this version, in the last goal of the predicate position/1, the list Crates is already restricted to a fixed length (=5) and to values between 1 and 5 when being labeled.

Then you want the chicken and the foxes to not be in the same crate: Chicken #\= Foxes. But according to the task description they are in different crates anyway. You rather want them to be not in adjacent crates. The same goes for ratpoison/barley and ratpoison/wheat. Also no two crates can be in the same position: you can use all_distinct/1 form library(clpfd) for that. Putting this all together you get something like:

:- use_module(library(clpfd)).

position(Crates) :-
    Crates = [Chicken, Barley, Foxes, RatPoison, Wheat],
    Crates ins 1..5,
    all_distinct(Crates),
    not_adjacent(Chicken,Foxes),
    not_adjacent(RatPoison,Barley),
    not_adjacent(RatPoison,Wheat),
    labeling([], Crates).

not_adjacent(X,Y) :-
    X #\= Y+1,
    Y #\= X+1.

Now try to query position/1:

   ?- position(Crates).
Crates = [1,2,4,5,3] ? ;
Crates = [1,3,4,5,2] ? ;
Crates = [1,4,3,2,5] ?
...

If you don't want to go through all solutions interactively you can use findall/3 and length/2 to show all solutions and to count them:

   ?- findall(Crates,position(Crates),L),length(L,X).
L = [[1,2,4,5,3],[1,3,4,5,2],[1,4,3,2,5],[1,5,3,2,4],[2,1,4,3,5],[2,1,4,5,3],[2,3,4,1,5],[2,3,4,5,1],[2,3,5,1,4],[2,4,5,1,3],[2,5,4,1,3],[2,5,4,3,1],[3,1,5,4,2],[3,2,5,4,1],[3,4,1,2,5],[3,5,1,2,4],[4,1,2,3,5],[4,1,2,5,3],[4,2,1,5,3],[4,3,1,5,2],[4,3,2,1,5],[4,3,2,5,1],[4,5,2,1,3],[4,5,2,3,1],[5,1,3,4,2],[5,2,3,4,1],[5,3,2,1,4],[5,4,2,1,3]],
X = 28

答案 1 :(得分:1)

My model gives different result WRT @tas answer. Maybe I don't fully understand the phrase

the chickens are separated from the foxes

that I translate like

abs(Chicken - Foxes) #> 2

Anyway, the full model

position(Crates) :-
    Crates = [Chicken, Barley, Foxes, RatPoison, Wheat],
    all_different(Crates),
    Crates ins 1..5,
    abs(Chicken - Foxes) #> 2,
    abs(RatPoison - Barley) #> 1,
    abs(RatPoison - Wheat) #> 1,
    label(Crates).

yields

?- aggregate(count,Cs^position(Cs),N).
N = 8.