我对限制编程很新,并试图找到一些真实情况来测试它。 我找到了一个我认为可以通过CP解决的问题。
这是: 我有一群孩子,我必须分配给一些活动。 这些孩子填写表格,按照优先顺序指定3个选项。 活动的参与者数量最多,因此,我们的想法是找到一个解决方案,在这个解决方案中,选择最佳,不超过最大值。
所以,在第一种方法中,我为域名[1,2,3]的孩子定义了变量(选择数量,活动和孩子在其他地方之间的联系)。
但是,我真的不知道如何定义相关的约束,所以我有所有的排列(非常长)然后,我必须给每个注释(添加选项的数量以获得最小值)和消除大群体的结果。
我认为使用CP必须有一个很好的方法来做到这一点,但我无法理解。
有人可以帮助我吗?
由于
答案 0 :(得分:2)
我不确定我是否理解你的描述中的所有内容,例如"所以我有所有的排列(非常长)"并且"我必须给每个人留言(添加选择的数量以获得最小值)"。也就是说,这是一个简单的编码,我认为这将是你的问题的模型,或者至少是一个启动器。
用MiniZinc编写,下面显示了6个孩子和4个活动的小例子。完整模型(包括一些约束的变体)也在这里:http://hakank.org/minizinc/max_activity.mzn
变量描述: " X"是一组决策变量,包含每个孩子的选定活动。 "得分"是所选活动的得分(1,2或3,取决于所选择的活动)," total_score"只是总结"得分"阵列。
include "globals.mzn";
int: num_kids;
array[1..num_kids, 1..3] of int: prefs;
int: num_activities;
array[1..num_activities] of int: activity_size;
% decision variables
array[1..num_kids] of var 1..num_activities: x; % the selected activity
array[1..num_kids] of var 1..num_activities: scores;
var int: total_score = sum(scores);
solve maximize total_score;
constraint
forall(k in 1..num_kids) (
% select one of the prefered activities
let {
var 1..3: p
} in
x[k] = prefs[k,p] /\
scores[k] = 4-p % score for the selected activity
)
/\ % ensure size of the activities
global_cardinality_low_up(x, [i | i in 1..num_activities], [0 | i in 1..num_activities], activity_size)
;
output [
"x : ", show(x), "\n",
"scores: ", show(scores), "\n",
"total_score: ", show(total_score), "\n",
];
%
% some small fake data
%
num_kids = 6;
num_activities = 4;
% Activity preferences for each kid
prefs = array2d(1..num_kids, 1..3,
[
1,2,3,
4,2,1,
2,1,4,
4,2,1,
3,2,4,
4,1,3
]);
% max size of activity
activity_size = [2,2,2,3];
此问题实例的解决方案是:
x : [1, 4, 2, 4, 3, 4]
scores: [3, 3, 3, 3, 3, 3]
total_score: 18
这是一个独特的解决方案。
使用稍小的activity_size([2,2,2,2])我们得到另一个最佳解决方案(total_score = 17),因为在活动#4中只有2个孩子(孩子#6在这里被迫采取活动#1代替)
x:[1,4,2,4,3,1] 分数:[3,3,3,3,3,2] total_score:17
第二种变体还有两种可能的选择,即
x : [1, 4, 2, 2, 3, 4]
scores: [3, 3, 3, 2, 3, 3]
total_score: 17
----------
x : [1, 2, 2, 4, 3, 4]
scores: [3, 2, 3, 3, 3, 3]
total_score: 17
更新:我还使用相同的主要方法做了一个Picat模型:http://hakank.org/picat/max_activity.pi。
更新2:上述模型假设所有孩子都获得了一些他们喜欢的活动。如果不满足这个假设,那么就会以某种方式解决这个问题,而不仅仅是抛出一个" UNSATISFIED"作为答案。一种方法是选择一些其他 - 不是首选的 - 活动来进行分数,这将得分为0.这在此模型中完成:http://hakank.org/minizinc/max_activity2.mzn
与原始模型相比的变化很小:
由于这是一个最大化问题,除非有必要,否则不会使用0分。
我还添加了一项健全性检查,确保所有孩子都有足够的活动:
constraint
assert(sum(activity_size) >= num_kids, "There is not activities enough for all kids.")
;