Minizinc搜索带有约束的{2}数组

时间:2016-01-30 20:15:26

标签: minizinc

如何从2d数组的每一行中选择最小的数字,同时确保最多可以选择相同的列两次 (在下面的例子中,对于第1行,选择第5列;对于第2行,选择第5列,而对于第3行,不能再选择第5列,因此选择第2列作为min): (此外,在java中,通常使用ArrayList来添加和删除元素,但是如何使用约束在Minizinc中执行此操作)?

int: m = 3;
int: n = 5;
array[1..m,1..n] of int: diffs = [|14,18,24,30,13
                                  |10,12,18,24,7
                                  | 8,7,12,18,6|]

1 个答案:

答案 0 :(得分:2)

以下是一种方法,可以最大限度地减少所选列和"真实值之间差异的总和。每行的最小值。

include "globals.mzn"; 
int: m = 3;
int: n = 5;
array[1..m,1..n] of int: diffs = [|14,18,24,30,13
                                  |10,12,18,24,7
                                  | 8,7,12,18,6|];

% decision variables
array[1..m] of var 1..n: x; % which row to select
var int: z; % difference between the selected and smallest values

solve minimize z;
% solve satisfy;

% constraint 1: at_most 2 of the same column can be selected
constraint
  % at most two rows can have the same column
  forall(j in 1..n) (
    at_most(2,x,j)
  )
; 

% constraint 2: calculate the least difference
constraint
  % get smallest difference to the smallest value
  z = sum(i in 1..m) (
       % value of selected column - the smallest value of the row
       diffs[i,x[i]]-min([diffs[i,j] | j in 1..n]) 
  )
  % /\ % for solve satisfy
  % z = 1
  ;

  output [
    "z: \(z)\n",
    "x: \(x)  values:\([diffs[i,x[i]] | i in 1..m])\n"
  ];

对于这个问题实例,有两个最优解,其中z = 1,即解决方案比"真实"最佳值(没有最大2列约束)。

 z: 1 
 x: [5, 5, 2]  values:[13, 7, 7]
 ----------
 z: 1 
 x: [1, 5, 5]  values:[14, 7, 6]

第一种解决方案意味着我们从第5列中为第2行(即13和7的值)选择值,对于第3行,我们从第2列中选择值(即7)。这恰好是示例中提到的解决方案。

有一种替代方法,其中约束2被替换为以下约束,即直接对所选值求和(而不是每行的最小值之差):

% constraint 2: calculate the least difference
constraint
  z = sum([diffs[i,x[i]] | i in 1..m])
  % /\ % for solve satisfy
  % z = 27
; 

它当然具有相同的列解决方案。区别仅在于" z":

的值
z: 27 
x: [5, 5, 2]  values:[13, 7, 7]
---------
z: 27 
x: [1, 5, 5]  values:[14, 7, 6]

可以说这个后来的变体更整洁,但是如果"差异和#34;矩阵很大,因此可能应该使用第一个变量,因为求解器更倾向于使用较小的值。 (对于具有较大值的矩阵,建议使用" z"而不是" var int"的限制域,但我今晚很懒。: - )