Вы можете использовать разные подходы, но подход, аналогичный тому, что вы пробуете, состоит в том, чтобы разделить подсчет различных элементов в массиве на два этапа:
- Подсчет появления значений в домене.
- Подсчет количества раз, когда вхождение больше нуля.
Мы можем использовать глобальное ограничение 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
. Однако я подозреваю, что с небольшими последствиями он будет работать достаточно хорошо.
person
Dekker1
schedule
06.10.2020