Minizinc:根据阵列位置设置枚举选项集,而不是所有阵列位置的选项集

问题描述

我熟悉这样的方法

set of int: RANGE = 1..5;
enum OPTS = {A,B,C};
array[RANGE] of var OPTS = result;

但是当我想为 OPTS 中的每个位置指定 RANGE 时怎么办?看起来像的东西

[{A,C},{A,B},C,D},{B,{A}]

然后生成 result[n] 以便它选择 n 处的可用选项之一。

我已尝试使用以下模型,但检测到模型不一致。

set of int: RANGE = 1..5;
enum OPTS = {A,D};
array[RANGE] of set of OPTS: t = [{A,{A}];
array[RANGE] of var OPTS: result;
constraint forall(i in RANGE)(
  forall(j in t[i])(
    result[i] = j
  )
);

output [show(result)]

可能的结果是 [B,A,D,A] - 最后一个位置 result[5] 不能是除 A 之外的任何其他位置。

我尝试使用 Minizinc 手册,但我无法理解如何使用规范中的示例,例如 https://www.minizinc.org/doc-2.4.3/en/spec.html#set-operations,它以其他知识(例如如何解释语法)为前提,我可能会花费无数小时试图追查在我的水平上的解释,因为搜索这些东西似乎真的没有结果。

谢谢!

解决方法

如果我理解正确,您可以使用 set of OPTS 来构造 OPTS 的数组,这里称为 t(您不能将其称为 output,因为它是保留字) .请注意,在您提出问题时,它不是 var 而是一个常量数组,因此在构造数组时不需要 var 关键字。

set of int: RANGE = 1..5;
enum OPTS = {A,B,C,D};
array[RANGE] of set of OPTS: t = [{A,C},{A,B},D},{B,{A}];

更新

这是更新问题的模型。这里的技巧是 t[i] 定义了 result[i] 的有效域,您可以简单地使用 in 来实现这一点。

set of int: RANGE = 1..5;
enum OPTS = {A,{A}];
array[RANGE] of var OPTS: result;

constraint 
  forall(i in RANGE) (
     % ensure that result[i] only takes the values in t[i]
     result[i] in t[i]
  )
;

output [show(result)]

这个问题有48种解决方案,例如:

[A,A,A]
----------
[B,A]
----------
[C,A]
----------
[A,A]
----------
...