具有一个域为1..N的具有自变量的列表,我们如何使用labeling / 2,以便它从中间开始生成解决方案?
我尝试过的标志是[二等分],[枚举],[最大],[最小],[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] ...
答案 0 :(得分:0)
您在这里!
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).
答案 1 :(得分:0)
根据经验,每当您尝试扩展clpfd的功能时,都应尝试尽可能多地重用。看来您首先要寻找到中心的距离之和尽可能小的解决方案。
date
答案 2 :(得分:0)
罗伯特·巴伦(Robert Baron)提供的答案正是我所需要的!我对其进行了编辑并添加了注释以了解它。这是评论版。
/* nsector(+N, +Sum, -Tuple)
* is true when Tuple is an n-tuple of positive
* integers that add up to Sum. The tuple solutions
* are recursively searched from the midpoint of
* the interval [1, S+1]. For example nsector(2,12, T)
* => [6,6];[7,5];[5,7];[8,4];[4,8];...;[11,1];[1,11]. */
nsector(2, S, L) :-
Z is S - 1,
bisector(Z, L).
nsector(N, S, [A | L]) :-
N > 2,
Z is S - 1,
bisector(Z, [A, B]),
D is N - 1,
nsector(D, B, L).
/* bisector(+Sum, -Pair)
* is true when Pair = [A, B] and S+1 is A+B, A,B > 0.
* The solutions are found by searching from the midpoint
* of the interval [1, S+1]. For example: bisector(6, P)
* => P = [4,3];[3,4];[5,2];[2,5];[6,1];[1,6].*/
bisector(Y, [A, B]) :-
odd(Y),
M is div(1 + Y, 2),
Z is M-1,
range(D, 0, Z),
even_interval(D, M, A, B).
bisector(Y, [A, B]) :-
even(Y),
M is 1 + Y,
Z is Y / 2 - 1,
range(D, 0, Z),
odd_interval(D, M, A, B).
/* even_interval(+D, +M, -A, -B)
* is true when A and B are at distance D from M, with A, B > 0.
* For example: even_interval(2, 6, A, B) => A = 8, B = 4; A= 4, B = 8 */
even_interval(0,M, M, M).
even_interval(D,M,A,B) :-
D > 0,
A is M + D,
A > 0,
B is M - D, B > 0.
even_interval(D,M,A,B) :-
D > 0,
A is M - D,
A > 0,
B is M + D,
B > 0.
/* odd_interval(+D, +M, -A, -B)
* is true when A and B are at distance D+1/2 from M/2, with A, B > 0.
* For example: odd_interval(2, 7, A, B) => A = 6, B = 1; A= 1, B = 6 */
odd_interval(D, M, A, B) :-
A is (M + 2 * D + 1) / 2,
A > 0,
B is (M - 2 * D - 1) / 2,
B > 0.
odd_interval(D, M, A, B) :-
A is (M - 2 * D - 1) / 2,
A > 0,
B is (M + 2 * D + 1) / 2,
B > 0.
/* even(+Integer)
* is true when Integer is even. */
even(Integer) :-
0 is mod(Integer, 2).
/* odd(+Integer)
* is true when Integer is odd. */
odd(Integer) :-
1 is mod(Integer, 2).
/* range(-Integer, +LowerBound, +UpperBound)
* is true when LowerBound <= Integer <= UpperBound. */
range(Integer, Integer, _).
range(Integer, LowerBound, UpperBound) :-
NewLowerBound is LowerBound + 1,
NewLowerBound =< UpperBound,
range(Integer, NewLowerBound, UpperBound).