需要帮助来定义适当的约束

时间:2014-09-12 11:07:08

标签: constraint-programming

我对限制编程很新,并试图找到一些真实情况来测试它。 我找到了一个我认为可以通过CP解决的问题。

这是: 我有一群孩子,我必须分配给一些活动。 这些孩子填写表格,按照优先顺序指定3个选项。 活动的参与者数量最多,因此,我们的想法是找到一个解决方案,在这个解决方案中,选择最佳,不超过最大值。

所以,在第一种方法中,我为域名[1,2,3]的孩子定义了变量(选择数量,活动和孩子在其他地方之间的联系)。

但是,我真的不知道如何定义相关的约束,所以我有所有的排列(非常长)然后,我必须给每个注释(添加选项的数量以获得最小值)和消除大群体的结果。

我认为使用CP必须有一个很好的方法来做到这一点,但我无法理解。

有人可以帮助我吗?

由于

1 个答案:

答案 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..num_activities
  • 我们添加了一个析取" /得分[k] = 0"到选择活动的forall循环

由于这是一个最大化问题,除非有必要,否则不会使用0分。

我还添加了一项健全性检查,确保所有孩子都有足够的活动:

constraint
  assert(sum(activity_size) >= num_kids, "There is not activities enough for all kids.")
;