MiniZinc计算数组中不同元素的数量

问题描述

我是约束编程和Minizinc的新手。 我一直在寻找解决方案,但并非一无所获。

我想计算数组中出现的不同元素的数量: 这是我的数组的声明:

Mediamuxer

我尝试这样做:

array[1..n,1..n] of var 1..n: countLeft;
  

但是显然我的数组的类型是:var opt int的array [int],并且不被array2set函数接受。

我快要疯了。 有人可以给我一个关于如何实现我想要做的事情的线索吗?会非常感激的(如果犯了一些错误,我很抱歉)

解决方法

您可能会采用不同的方法,但是一种与您尝试的方法类似的方法是将数组中不同元素的计数分为两个步骤:

  1. 计算域中值的出现。
  2. 计算发生次数大于零的次数。

我们可以使用全局global_cardinality约束对出现的次数进行计数,然后对其结果使用简单的计数约束。

include "global_cardinality_fn";

array[1..n] of var int: occurrences = global_cardinality(YOURARRAY,[i | i in 1..n]);

var int: num_diff = count(o in occurrences) (o > 0);

但是,请注意,这可能不是您模型的最佳代码。对于某些求解器,global_cardinality可能表现不佳。同样,如果您的stopCountLeft包含变量,则意味着您正在创建一个可选变量数组,并且可能没有为可选变量定义global_cardinality

相反,我们可以改写一个蕴涵图。这个想法仍然是相同的,但是我们没有使用计数值的数量,而是使用布尔值来表示该值是否正在使用。

array[1..n] of var bool: occurs;

constraint forall(i,j in 1..n) (YOURARRAY[i] = j -> occurs[j]);

var int: num_diff = count(occurs);

请注意,此方法的问题在于在forall循环中发布的含义的指数数量。但是,我怀疑它的影响很小,因此效果会相当不错。

,

MiniZinc 2.5.0中,您可以执行以下操作:

array[int,int] of int: a = 
  [| 1,1,| 2,3,| 3,4 |];

set of int: Rows = index_set_1of2(a);
set of int: Cols = index_set_2of2(a);

int: values = card({ a[r,c] | r in Rows,c in Cols });

output ["\(values) values in "] ++ 
       [if c == 1 then "\n" else "" endif ++ 
        "\(a[r,c]) " | r in Rows,c in Cols];