我不知道我理解你的描述的一切,例如:“所以我把所有的置换(很长)”和“我给了一张字条给每个(添加数字的选择获得最小值)“。也就是说,这是一个简单的编码,我认为这是你问题的一个模型,或者至少是一个初学者。
它是用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
这是一个独特的解决方案。我们得到了另一个最优的解决方案(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:上述模型假定所有的孩子都会得到一些他们喜欢的活动。当这个假设没有得到满足时,人们就会以某种方式解决这个问题,而不是仅仅抛出一个“无法接受”作为答案。一种方法是选择一些其他的 - 不是首选 - 活动的孩子,这将产生一个得分的0。这在这个模型做:http://hakank.org/minizinc/max_activity2.mzn
相比原车型的变化较小:
- 的“得分”的域是0..num_activities
- 我们添加一个脱节“/分数[K] = 0”到forall的环,其选择的活性
由于这是一个最大化问题的得分除非必要,否则不会使用0。
我还添加了一个合理性检查,有足够的活动,为所有的孩子:
constraint
assert(sum(activity_size) >= num_kids, "There is not activities enough for all kids.")
;
谢谢。我不知道MiniZinc,我会看看它。 – fatbob 2014-09-13 10:44:08
只是为了澄清:“我拥有所有的排列组合”,意味着我没有设置约束条件,我的程序给了我所有可能的解决方案(当你有很多孩子时,这个方案很长),然后,我必须选择好的,给返回的解决方案打分。注意我选择的解决方案的方法是,如果活动与孩子的选择1相对应,则选择1,如果选择2,则选择2 ......最终得分是这些得分的总和,最小值对我来说是最好的。乍一看,你的解决方案似乎回答。 – fatbob 2014-09-13 10:54:22
感谢您的澄清。我还添加了第二个模型,可以处理没有足够的首选活动时的情况;请参阅“更新2”。 – hakank 2014-09-13 17:51:24