CPLEX OPL中单货运最多服务2个客户的约束编码方法
OPL实现单班次收货客户数不超过2个的约束方案
核心逻辑:由于约束统计的是去重后的客户ID数量,而非订单数量,因此不能直接通过订单分配变量计数,需要引入辅助0-1变量标记「某客户是否有订单被分配到对应班次」,再对单班次的标记值做上限约束。
具体编码步骤
1. 补充集合与辅助变量定义
在原有决策变量Assignment的定义段后,新增全量客户集合、客户-班次使用标记变量:
// 提取所有订单涉及的不重复客户ID集合 {string} AllClients = {o.ClientId | o in Orders}; // 辅助0-1变量:ClientUse[c][f] = 1 代表客户c有订单分配到班次f,为0则代表无 dvar boolean ClientUse[AllClients][FreightTypes];
2. 在约束块新增对应规则
在subject to块中补充两组约束,替换原有未写完的c2注释即可:
subject to{ //c1: 所有订单必须全部分配完成履约 forall(o in Orders) sum(f in FreightTypes) Assignment[o][f]==1; //c2: 关联订单分配变量与客户使用标记:客户只要有1个订单分到该班次,标记必须置1 forall(c in AllClients, f in FreightTypes) sum(o in Orders: o.ClientId == c) Assignment[o][f] <= ClientUse[c][f] * count(o in Orders: o.ClientId == c); //c3: 单个货运班次承载的不同收货ClientId数量不得超过2个 forall(f in FreightTypes) sum(c in AllClients) ClientUse[c][f] <= 2; }
约束逻辑说明
- c2约束的不等式左侧是「客户c在班次f上分配到的订单总数」,右侧是客户标记值乘以该客户的总订单数:
- 只要左侧≥1(即客户有订单分到该班次),
ClientUse[c][f]必须取1才能满足不等式,否则右侧值为0,会小于左侧正数导致约束不成立 - 如果左侧=0(客户无订单分到该班次),
ClientUse[c][f]取0即可满足约束,且由于c3限制了单班次客户数上限,求解器为了拿到最低成本,不会无故将标记置1占用名额,无需额外添加反向约束。
- 只要左侧≥1(即客户有订单分到该班次),
示例数据求解效果
新增约束前,求解器会选择成本最低的30000元DURHAM班次承运全部3个订单;新增约束后,由于3个订单分属3个不同ClientId,该班次最多只能承载2个订单,剩余1个订单需要分配到其他40000元的班次,最终最低总成本为70000元,符合业务规则要求。
内容的提问来源于stack exchange,提问作者william007
相关产品推荐
相关产品推荐

