Как маркировка / 2 может генерировать решения, начиная с середины домена? - PullRequest
1 голос
/ 23 мая 2019

Имея список с независимыми переменными, чей домен равен 1..N, как мы можем использовать маркировку / 2, чтобы она начинала создавать решения, начиная с середины?

Флаги, которые я пробовал: [bisect], [enum], [max], [min], [ff], но независимо от того, что я выбрал, я не могу заставить их работать.

Мой код:

:-use_module(library(clpfd)).

combos(EMPLOYEES,POSTS,LIST):-
   LIMIT is POSTS-EMPLOYEES+1,
   length(LIST,EMPLOYEES),
   LIST ins 1..LIMIT,
   sum(LIST,#=,POSTS),
   labeling([bisect],LIST).

после установки запроса, например:

?-combos(2,10,LIST).

Я хочу, чтобы он вернулся:

L = [5,5];
L = [4,6];
L = [6,4] ...

вместо:

L = [1,9];
L = [2,8];
L = [3,7] ...

Ответы [ 2 ]

1 голос
/ 24 мая 2019

Как правило, всякий раз, когда вы пытаетесь расширить функциональность clpfd, старайтесь использовать как можно больше.Похоже, что сначала вам нужны решения, у которых сумма расстояний до центра как можно меньше.

combos2(EMPLOYEES,POSTS,LIST):-
   LIMIT is POSTS-EMPLOYEES+1,
   length(LIST,EMPLOYEES),
   LIST ins 1..LIMIT,
   sum(LIST,#=,POSTS),
   Mid is (LIMIT+1) div 2,           %%
   maplist(dist(Mid), LIST, DISTS),  %%    
   sum(DISTS,#=,Totaldist),          %%
   labeling([],[Totaldist|LIST]).

dist(Mid, E, D) :-
    D #= abs(Mid-E).

?- combos2(2,10,L).
   L = [5,5]
;  L = [4,6]
;  L = [6,4]
;  L = [3,7]
;  L = [7,3]
;  ...
0 голосов
/ 23 мая 2019

Вот, пожалуйста!

combos(2,S,L) :- b2(S,L).
combos(C,S,[A|L]) :-
    C > 2,
    b2(S,[A,B]),
    D is C-1,
    combos(D,B,L).

b2(S,L) :- B is S-1, bisector(B,L).

bisector(Y,[A,B]) :-
    odd(Y),
    M is div(1+Y,2),
    Z is M-1,
    range(D,0,Z),
    bisec1(D,M,A,B).
bisector(Y,[A,B]) :-
    even(Y),
    M is 1+Y,
    Z is Y/2-1,
    range(D,0,Z),
    bisec2(D,M,A,B).

bisec1(0,M,M,M).
bisec1(D,M,A,B) :- D > 0, A is M + D, A > 0, B is M - D, B > 0.
bisec1(D,M,A,B) :- D > 0, A is M - D, A > 0, B is M + D, B > 0.

bisec2(D,M,A,B) :- A is (M+2*D+1)/2, A > 0, B is (M-2*D-1)/2, B > 0.
bisec2(D,M,A,B) :- A is (M-2*D-1)/2, A > 0, B is (M+2*D+1)/2, B > 0.

even(X) :- 0 is mod(X, 2).
odd(X) :- 1 is mod(X, 2).

range(M,M,_).
range(X,M,N) :- P is M + 1, P =< N, range(X,P,N).
...