我有一种情况,我正在建模数组S
,其中包含来自预定义域1..t
的一组值(一个计划),加上0
,这是一个特殊值for" not there / not used"。
我现在想要发布一个约束来对列表C
的成本函数求和,表示为2D数组S'
,并保留S
中的每个非零元素。同样的顺序,如下:
constraint x = sum([C[S'[d], S'[d + 1]] | d in 1..max - 1])
但是,这不容易做到。我尝试过的事情:
roots
的函数形式获取数据为非零的S
索引集。该解决方案的问题是:
[S[i] | i in 1..max where S[i] != 0]
)仅选择值为非零的元素:这也不起作用,因为列表推导的where
子句导致列表属于opt
类型,并且元素数量错误(我假设其中一些元素将为<>
),从而基本上减少了使用{{再次将零过滤到同一问题的问题1}}:S。我真正想要的是<>
或filter
,这可以很容易地解决我的问题,但我认为我缺少某种标准解决方案。否则,我将不得不重新设计模型。
答案 0 :(得分:5)
可以通过使用递归函数来解决您的问题,该递归函数通过迭代数组S
的索引来计算成本。我在一个小例子中说明了下面的函数calculate_cost()
:
int: t = 10; int: N = 5;
% cost array
array[1..t,1..t] of int: C = array2d(1..t,1..t,[ i | i in 1..t, j in 1..t]);
% variables
array[1..N] of var 0..t: S;
var 0..1000: x;
% constraints
constraint S[1] = 4; % setting some arbitrary values
constraint S[2] = 7;
constraint S[3] = 0;
constraint S[4] = 6;
constraint x = calculate_cost(1,2);
function var int: calculate_cost(int: index1, int:index2) =
if index1 > N then 0
elseif index2 > N then 0
else
let {
var bool: value_at_index1_is_zero = S[index1] == 0;
var bool: value_at_index2_is_zero = S[index2] == 0;
}
in
if value_at_index1_is_zero
then calculate_cost(index1+1, index1+2)
elseif value_at_index2_is_zero
then calculate_cost(index1, index2 + 1)
else
C[S[index1],S[index2]] + calculate_cost(index2, index2+1)
endif
endif;
solve satisfy;
此示例包含S = [4, 7, 0, 6, 0]
并计算费用x = C[4,7] + C[7,6] = 4 + 7 = 11
。
在函数calculate_cost()
中,我通过跳过S
中零值的索引来递归计算总和。在前几行中,我检查索引是否超出范围并在这种情况下返回0(递归的基本情况)。然后,如果true
的{{1}}值为零,则创建两个S[index]
的局部变量。然后,如果其中一种情况属实,我忽略这些索引,并递归地再次调用该函数,并在递归调用中增加/调整相应的索引。
这可行,但可能不是解决此问题的一种非常好的方法,因为它在FlatZinc模型中引入了许多辅助变量,因此重新解决问题可能仍然更好。