计算Minizinc数组中最频繁的元素

时间:2020-07-06 15:31:52

标签: arrays count minizinc

这是我想在Minizinc中做的一件非常简单的事情。我有一个整数值数组,我想知道最常见值出现的次数。我不知道该怎么做。我希望有人能提供帮助。

2 个答案:

答案 0 :(得分:3)

解决此问题的“经典”方法是将全局约束global_cardinalitymax一起使用。

下面是使用这些约束对该问题进行建模的一种方法。并且还会显示最频繁的号码。

使用此方法的缺点是必须创建一个新数组gcc(用于“全局基数计数”),其中包括每个数字0..upb的出现次数(其中{{1 }}是数组upb的上限,如果数组中的数字很大,则可能会很大。另外,必须对索引稍加注意,例如别忘了在a中加入0。

这种方法的优点-除了可以在求解器中高效实现之外-可以在gcc数组上添加一些额外的约束:在这里,我添加了此功能来显示最频繁(使用gcc);这样的数字可能不止一个,然后会给出多个解决方案。

arg_max(a)

以下是该模型的输出:

include "globals.mzn";   

int: n = 7;
array[1..n] of int: a = [15, 14, 39, 23, 14, 14, 8];
% array[1..n] of var 0..29: a; % using decision variables

% upper value of a
int: upb = ub_array(a);

% Number of occurrences in a
array[0..upb] of var 0..n: gcc;

% max number of occurrenes
var 0..upb: z = max(gcc);

% The value of the max number of occurrences
var 0..upb: max_val = arg_max(gcc)-1;

solve satisfy;

constraint
    % count the number of occurrences in a
    global_cardinality(a, array1d(0..upb,[i | i in 0..upb]), gcc)
;

output [
    "a: \(a)\n",
    "upb: \(upb)\n",
    "gcc: \(gcc)\n",
    "z: \(z)\n",
    "max_val: \(max_val)\n",        
    "ub_array(a): \(lb_array(a))..\(ub_array(a))\n",
  ];

答案 1 :(得分:2)

我不知道这是否是最有效的方法,但是它起作用了,基本上,对于数组中的每个元素,您求和该值出现在数组中的次数并将其存储在辅助数组中,然后取查找在辅助数组中出现的最大值,因此在示例14中出现3次,因此repeats对于对应于14的每个元素保留3。
最后,我添加了上面所有内容的一个线性版本,在这里您无需生成repeats的数组,而是在max_repeats的行中生成它。

% count the number of times that the most common value is repeated in an array
% As an example lets make a 7 element array
% size
int : n = 7;
% index set
set of int : SET = 1..n;
% the values
array [SET] of int : x = [15,14,39,23,14,14,8];
% auxiliar variable to carry the count
array [SET] of var int : repeats;

% we will count the number of times that value repeats
constraint forall(i in SET)(repeats[i] = sum(j in SET)(x[i] = x[j]) );

% the value of the most repeated element in the array
var int : value;
% if the number of repeats of that element is the maximum 
% then value is equal to that element
constraint forall(i in SET)(repeats[i] = max(repeats) -> value = x[i]);

% this does the same but in one line
var int : max_repeats = max([sum(j in SET)(x[i] = x[j]) | i in SET]);

solve satisfy;

output ["Original values " ++ show(x) ++ "\n"] ++
       ["Number of repeats of each element " ++ show(repeats) ++ "\n"] ++ 
       ["Maximum number of repeats : " ++ show(max(repeats))];
Original values [15, 14, 39, 23, 14, 14, 8]
Number of repeats of each element [1, 3, 1, 1, 3, 3, 1]
Maximum number of repeats : 3