如何在Lingo中定义依赖集合?附订单分配建模场景
如何在Lingo中定义依赖于工厂的机器集合?
某企业拥有5个工厂,各工厂的机器数量分别为3、4、5、2、3台,需将20份订单分配至各工厂的对应机器,成本仅与订单所属工厂相关。当前建模默认所有工厂都拥有17台机器,实际需求为:
- 1号工厂对应本地机器编号1-3(或全局编号1-3)
- 2号工厂对应本地机器编号1-4(或全局编号4-7)
- 3号工厂对应本地机器编号1-5(或全局编号8-12)
- 4号工厂对应本地机器编号1-2(或全局编号13-14)
- 5号工厂对应本地机器编号1-3(或全局编号15-17)
需要定义依赖于工厂的机器集合,避免无效的工厂-机器组合。
原模型代码
Model: Sets: orders/1..20/:; plants/1..5/:; machines/1..17/:; allocation(orders, plants): c; assign(orders, plants, machines): x; end sets data: c = 1 2 3 4 5 6 7 8 9 10 10 9 8 7 6 5 4 3 2 1 1 2 3 4 5 6 7 8 9 10 10 9 8 7 6 5 4 3 2 1 1 2 3 4 5 6 7 8 9 10 10 9 8 7 6 5 4 3 2 1 1 2 3 4 5 6 7 8 9 10 10 9 8 7 6 5 4 3 2 1 1 2 3 4 5 6 7 8 9 10 10 9 8 7 6 5 4 3 2 1; end data min = @sum(assign(i, j, k): c(i, j) * x(i, j, k)); @for(orders(i): @sum(plants(j): @sum(machines(k): x(i, j, k))) = 1); @for(assign(i, j, k): @bin(x(i, j, k))); end
解决方案
方案一:使用本地机器编号(嵌套派生集合)
给每个工厂分配独立的本地机器编号(从1开始计数),通过嵌套派生集合实现依赖关系:
Model: Sets: orders/1..20/:; plants/1..5/: machine_count; // 存储每个工厂的机器数量 // 嵌套集合:每个工厂j对应的本地机器编号1到machine_count(j) machines_by_plant(plants, *):; allocation(orders, plants): c; // 订单分配到工厂j的本地机器k assign(orders, machines_by_plant): x; End Sets Data: machine_count = 3 4 5 2 3; // 各工厂的机器数量 c = 1 2 3 4 5 6 7 8 9 10 10 9 8 7 6 5 4 3 2 1 1 2 3 4 5 6 7 8 9 10 10 9 8 7 6 5 4 3 2 1 1 2 3 4 5 6 7 8 9 10 10 9 8 7 6 5 4 3 2 1 1 2 3 4 5 6 7 8 9 10 10 9 8 7 6 5 4 3 2 1 1 2 3 4 5 6 7 8 9 10 10 9 8 7 6 5 4 3 2 1; End Data // 生成每个工厂对应的本地机器集合 @for(plants(j): machines_by_plant(j, 1..machine_count(j))); // 目标函数:最小化总分配成本 min = @sum(assign(i, j, k): c(i, j) * x(i, j, k)); // 约束1:每个订单必须分配到一台机器 @for(orders(i): @sum(machines_by_plant(j, k): x(i, j, k)) = 1); // 约束2:分配变量为二进制(0=未分配,1=已分配) @for(assign(i, j, k): @bin(x(i, j, k))); end
方案二:使用全局机器编号(带过滤条件的派生集合)
如果需要保留全局机器编号(1-17),通过过滤条件定义仅包含工厂对应全局机器范围的集合:
Model: Sets: orders/1..20/:; plants/1..5/: start_machine, end_machine; // 每个工厂对应的全局机器起止编号 machines/1..17/:; allocation(orders, plants): c; // 过滤条件:仅包含工厂j对应的全局机器k(k在start到end之间) assign(orders, plants, machines) | k #ge# start_machine(j) #and# k #le# end_machine(j): x; End Sets Data: // 各工厂对应的全局机器范围 start_machine = 1 4 8 13 15; end_machine = 3 7 12 14 17; c = 1 2 3 4 5 6 7 8 9 10 10 9 8 7 6 5 4 3 2 1 1 2 3 4 5 6 7 8 9 10 10 9 8 7 6 5 4 3 2 1 1 2 3 4 5 6 7 8 9 10 10 9 8 7 6 5 4 3 2 1 1 2 3 4 5 6 7 8 9 10 10 9 8 7 6 5 4 3 2 1 1 2 3 4 5 6 7 8 9 10 10 9 8 7 6 5 4 3 2 1; End Data // 目标函数:最小化总分配成本 min = @sum(assign(i, j, k): c(i, j) * x(i, j, k)); // 约束1:每个订单必须分配到一台机器 @for(orders(i): @sum(assign(i, j, k): x(i, j, k)) = 1); // 约束2:分配变量为二进制 @for(assign(i, j, k): @bin(x(i, j, k))); end
两种方案的区别
- 方案一用本地编号,逻辑更直观,适合无需跟踪全局机器编号的场景;
- 方案二保留全局编号,适合需要明确对应具体物理机器的场景。
内容的提问来源于stack exchange,提问作者Ceria FM Tantrika
相关产品推荐
相关产品推荐

