You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在MiniZinc中对集合元素求和?活动分区场景实现疑问

集合类型变量的求和问题(约束规划)

需求是将活动划分到多个集合(每个集合对应一个时间段),每个活动有允许开展的时段范围。现有MiniZinc代码定义了Schedule数组等变量,但在计算每个时间段的活动总和(后续将替换为活动成本)时,因Schedule是集合类型,内置sum函数不支持直接求和,需要调整实现方式。

原代码(补充缺失的ACTIVITY定义)

int: nb_act = 6; % 活动数量
set of int: ACTIVITY = 1..nb_act; % 活动集合
set of int: window_1 = {1,2,3}; % 活动1允许的时间段集合
array[1..nb_act] of var 0..nb_act: day_cost; % 每个时间段的活动总成本

array[1..nb_act] of var set of ACTIVITY: Schedule; % 将活动划分为6个集合,每个集合对应一个时间段
% 每个时间段的活动数量无限制,最多所有活动在同一天,最少每天一个活动

var 0..nb_act: day_cost_1; % 时间段1的活动总成本

constraint partition_set([Schedule[i] | i in 1..nb_act], ACTIVITY); % 所有时间段的活动集合构成完整划分
constraint Schedule[1] subset window_1; % 原约束逻辑有误,Schedule[1]是活动集合,window_1是时间段集合,此处逻辑不匹配

constraint 
  day_cost_1 = sum(Schedule[1]); % 报错:sum不支持集合类型

解决办法

1. 修正约束逻辑(先明确活动与时间段的对应关系)

原代码中Schedule[1] subset window_1逻辑错误:Schedule[1]是活动集合,window_1是时间段集合,两者类型不匹配。正确约束应为「活动1所在的时间段属于window_1」,可以新增数组记录活动对应的时间段,让逻辑更清晰:

array[ACTIVITY] of var 1..nb_act: act_slot; % act_slot[a]表示活动a所在的时间段

% 建立活动与Schedule集合的关联:活动a在时间段d,当且仅当a属于Schedule[d]
constraint forall(a in ACTIVITY, d in 1..nb_act) (
  a in Schedule[d] <-> act_slot[a] = d
);

% 活动1的时间段限制
constraint act_slot[1] in window_1;

2. 实现集合的求和计算

MiniZinc的sum函数仅支持对数组或枚举项求和,要计算某个时间段的活动总和(或成本),需遍历所有活动,判断该活动是否属于当前时间段的集合后再累加对应值:

  • 计算活动数量:
constraint day_cost_1 = sum(a in ACTIVITY) (
  if a in Schedule[1] then 1 else 0 endif
);
  • 计算活动成本(先定义成本数组):
array[ACTIVITY] of int: cost = [2,3,1,4,5,2]; % 示例:每个活动的成本
constraint day_cost_1 = sum(a in ACTIVITY) (
  if a in Schedule[1] then cost[a] else 0 endif
);

3. 批量计算所有时间段的成本

如果要一次性计算所有day_cost的值,不用逐个写约束,可用数组推导式批量处理:

constraint forall(d in 1..nb_act) (
  day_cost[d] = sum(a in ACTIVITY) (
    if a in Schedule[d] then cost[a] else 0 endif
  )
);

内容的提问来源于stack exchange,提问作者Waldo

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.16 06:45:34