Minizinc:int数组的成对交集

时间:2017-05-16 18:20:07

标签: intersection constraint-programming minizinc

我有一些数组(可能超过10个)的int变量。我正在寻找一种有效的方法来约束这些数组的成对交叉计数,即每个数组不能有超过x个元素与任何其他数组共同。

伪代码的例子:[1,4,4]和[2,2,1]将有一个共同的元素 - >数字1 [4,4,4]和[9,4,4]有共同的元素4,副本4应该被忽略。

在我当前的实现中,我迭代所有数组对,并且每个元素检查每个元素是否也在另一个数组中。这当然是非常缓慢的,并且副本不会像它们应该那样被消除。

我的代码中有趣的部分如下所示:

constraint matches [0] = exists ( i in index_set(values1) ) ( values1[i]==values2[0] );
constraint matches [1] = exists ( i in index_set(values1) ) ( values1[i]==values2[1] );
constraint matches [2] = exists ( i in index_set(values1) ) ( values1[i]==values2[2] );
constraint matches [3] = exists ( i in index_set(values1) ) ( values1[i]==values2[3] );
constraint matches [4] = exists ( i in index_set(values1) ) ( values1[i]==values2[4] );

constraint sum(matches) <  x;

我已经考虑过使用minizinc集,因为它们支持一些集合操作,但是我无法让它们使用变量。

有什么想法吗?

1 个答案:

答案 0 :(得分:0)

也许是这样的,使用array2set将数组转换为集合,然后cardintersect计算每对之间的交叉点数。

int: rows = 4; % number of columns
int: cols = 5; % number of rows
array[1..rows,1..cols] of int: a = array2d(1..rows,1..cols, 
               [
               4,6,9,5,6,
               5,3,7,1,3,
               3,8,3,3,1,
               1,1,4,7,2,
               ]);
% convert the arrays to sets
array[1..rows] of set of int: s = [array2set([a[i,j] | j in 1..cols]) | i in 1..rows];

% decision variables
var int: z;

solve satisfy;
constraint
    z = sum(r1,r2 in 1..rows where r1 < r2) (
              card(s[r1] intersect s[r2])
        )
;
output 
[
  "z:\(z)\n"
] ++
[
  show(s[i]) ++ "\n"
  | i in 1..rows 
];

此模型的输出是

z:7
{4,5,6,9}
{1,3,5,7}
{1,3,8}
{1,2,4,7}