设置分区
Set partitioning
我试图很好地理解这个问题,但我很吃力。
假设我有一个 S={1,2,3,4,5},一个 L={(1,3,4),(2,3),(4,5),(1,3), (2),(5)} 和另一个具有 L 成本的元组,例如 C={10,20,12,15,4,10}
我想在Prolog中做一个约束程序,以便以最小的成本得到解决问题的解决方案。(在这种情况下,它是我将得到的子集的成本总和)
我的问题是我无法理解我进行建模的方式。我所知道的是我应该选择二进制变量 {0,1} 的模型化,但我几乎不明白我将如何设法通过 Prolog 来表达它。
有一种简单的方法:您可以使用布尔值 指标 来表示哪些元素构成子集。例如,在您的情况下:
subsets(Sets) :-
Sets = [[1,0,1,1,0]-10, % {1,3,4}
[0,1,1,0,0]-20, % {2,3}
[0,0,0,1,1]-12, % {4,5}
[1,0,1,0,0]-15, % {1,3}
[0,1,0,0,0]-4, % {2}
[0,0,0,0,1]-10]. % {5}
我现在使用 SICStus Prolog 及其 Boolean constraint solver 来表达集合封面:
:- use_module(library(lists)).
:- use_module(library(clpb)).
setcover(Cover, Cost) :-
subsets(Sets),
keys_and_values(Sets, Rows, Costs0),
transpose(Rows, Cols),
same_length(Rows, Coeffs),
maplist(cover(Coeffs), Cols),
labeling(Coeffs),
phrase(coeff_is_1(Coeffs, Rows), Cover),
phrase(coeff_is_1(Coeffs, Costs0), Costs),
sumlist(Costs, Cost).
cover(Coeffs, Col) :-
phrase(coeff_is_1(Col,Coeffs), Cs),
sat(card([1],Cs)).
coeff_is_1([], []) --> [].
coeff_is_1([1|Cs], [L|Ls]) --> [L], coeff_is_1(Cs, Ls).
coeff_is_1([0|Cs], [_|Ls]) --> coeff_is_1(Cs, Ls).
对于每个子集,一个布尔变量用于表示该子集是否是封面的一部分。基数约束确保每个元素恰好被覆盖一次。
示例查询及其结果:
| ?- setcover(Cover, Cost).
Cover = [[0,0,0,1,1],[1,0,1,0,0],[0,1,0,0,0]],
Cost = 31 ? ;
Cover = [[1,0,1,1,0],[0,1,0,0,0],[0,0,0,0,1]],
Cost = 24 ? ;
no
我把选择一个成本最低的封面作为一个简单的练习。
也许您的问题实例的显式模型可以使事情变得更清楚:
cover(SetsUsed, Cost) :-
SetsUsed = [A,B,C,D,E,F], % a Boolean for each set
SetsUsed #:: 0..1,
A + D #= 1, % use one set with element 1
B + E #= 1, % use one set with element 2
A + B + D #= 1, % use one set with element 3
A + C #= 1, % use one set with element 4
C + F #= 1, % use one set with element 5
Cost #= 10*A + 20*B + 12*C + 15*D + 4*E + 10*F.
你可以解决这个问题,例如在 ECLiPSe:
?- cover(SetsUsed,Cost), branch_and_bound:minimize(labeling(SetsUsed), Cost).
SetsUsed = [1, 0, 0, 0, 1, 1]
Cost = 24
Yes (0.00s cpu)
我试图很好地理解这个问题,但我很吃力。 假设我有一个 S={1,2,3,4,5},一个 L={(1,3,4),(2,3),(4,5),(1,3), (2),(5)} 和另一个具有 L 成本的元组,例如 C={10,20,12,15,4,10}
我想在Prolog中做一个约束程序,以便以最小的成本得到解决问题的解决方案。(在这种情况下,它是我将得到的子集的成本总和)
我的问题是我无法理解我进行建模的方式。我所知道的是我应该选择二进制变量 {0,1} 的模型化,但我几乎不明白我将如何设法通过 Prolog 来表达它。
有一种简单的方法:您可以使用布尔值 指标 来表示哪些元素构成子集。例如,在您的情况下:
subsets(Sets) :- Sets = [[1,0,1,1,0]-10, % {1,3,4} [0,1,1,0,0]-20, % {2,3} [0,0,0,1,1]-12, % {4,5} [1,0,1,0,0]-15, % {1,3} [0,1,0,0,0]-4, % {2} [0,0,0,0,1]-10]. % {5}
我现在使用 SICStus Prolog 及其 Boolean constraint solver 来表达集合封面:
:- use_module(library(lists)). :- use_module(library(clpb)). setcover(Cover, Cost) :- subsets(Sets), keys_and_values(Sets, Rows, Costs0), transpose(Rows, Cols), same_length(Rows, Coeffs), maplist(cover(Coeffs), Cols), labeling(Coeffs), phrase(coeff_is_1(Coeffs, Rows), Cover), phrase(coeff_is_1(Coeffs, Costs0), Costs), sumlist(Costs, Cost). cover(Coeffs, Col) :- phrase(coeff_is_1(Col,Coeffs), Cs), sat(card([1],Cs)). coeff_is_1([], []) --> []. coeff_is_1([1|Cs], [L|Ls]) --> [L], coeff_is_1(Cs, Ls). coeff_is_1([0|Cs], [_|Ls]) --> coeff_is_1(Cs, Ls).
对于每个子集,一个布尔变量用于表示该子集是否是封面的一部分。基数约束确保每个元素恰好被覆盖一次。
示例查询及其结果:
| ?- setcover(Cover, Cost). Cover = [[0,0,0,1,1],[1,0,1,0,0],[0,1,0,0,0]], Cost = 31 ? ; Cover = [[1,0,1,1,0],[0,1,0,0,0],[0,0,0,0,1]], Cost = 24 ? ; no
我把选择一个成本最低的封面作为一个简单的练习。
也许您的问题实例的显式模型可以使事情变得更清楚:
cover(SetsUsed, Cost) :-
SetsUsed = [A,B,C,D,E,F], % a Boolean for each set
SetsUsed #:: 0..1,
A + D #= 1, % use one set with element 1
B + E #= 1, % use one set with element 2
A + B + D #= 1, % use one set with element 3
A + C #= 1, % use one set with element 4
C + F #= 1, % use one set with element 5
Cost #= 10*A + 20*B + 12*C + 15*D + 4*E + 10*F.
你可以解决这个问题,例如在 ECLiPSe:
?- cover(SetsUsed,Cost), branch_and_bound:minimize(labeling(SetsUsed), Cost).
SetsUsed = [1, 0, 0, 0, 1, 1]
Cost = 24
Yes (0.00s cpu)