用Yalmip玩转0-1变量:从物流选址到逻辑约束的5个经典案例
如果你曾经被那些“要么选,要么不选”的决策问题困扰过——比如到底在哪个城市建仓库最划算,或者如何安排生产线才能让机器开关最省电——那么你其实已经摸到了离散优化的大门。这类问题里,决策变量往往不是连续变化的数字,而是非此即彼的二元选择。在MATLAB的Yalmip建模工具箱里,binvar就是专门用来定义这种0-1变量的利器。但很多工程师的认知可能就停留在“哦,binvar就是定义0-1变量”,然后照着模板写几行代码。这就像只学会了螺丝刀的握法,却从没想过它能拧出多么精密的机械结构。
实际上,binvar的潜力远不止于简单的“是/否”标记。它更像是一把逻辑建模的瑞士军刀,能够将现实世界中复杂的“如果...那么...”、“至少满足一个”、“不能同时发生”等业务规则,转化为优化求解器(如Gurobi、CPLEX)能够理解的线性或二次约束。掌握它,意味着你能将许多看似棘手的运营难题,转化为可计算、可优化的数学模型。本文将从五个源自工业实践的经典案例出发,不仅展示binvar的基础用法,更深入剖析如何用“大M法”等技巧处理复杂的逻辑关系与分段函数,并分享在Gurobi求解器下提升求解效率的参数调优心得。我们的目标是,让你手里的binvar从一把简单的起子,变成一套能解决复杂工程问题的组合工具。
1. 案例一:多仓库选址与容量分配——构建成本最优的物流网络
想象一下,你是一家电商公司的物流规划师。公司业务扩张,需要在华北地区的五个候选城市(北京、天津、石家庄、太原、济南)中,选择至多三个城市建立区域性配送中心。每个城市建仓有固定的建设成本(如土地、基建),并且每个仓库有最大处理容量限制。你的任务是在满足所有城市客户需求的前提下,最小化总成本(建设成本+运输成本)。
这是一个典型的设施选址问题(Facility Location Problem)。binvar在这里的核心作用是决定在哪个城市建仓(建或不建)。我们首先定义决策变量:
% 假设有5个候选地点,20个需求点
num_sites = 5;
num_customers = 20;
% 决策变量
% y_i = 1 表示在第i个候选地点建仓,否则为0
y = binvar(num_sites, 1, 'full');
% x_ij 表示从仓库i运往客户j的货物量(连续变量)
x = sdpvar(num_sites, num_customers, 'full');
接下来是目标函数和约束。目标是最小化总成本,包括固定建设成本和可变运输成本:
% 参数:固定建设成本f_i, 单位运输成本c_ij, 仓库容量cap_i, 客户需求d_j
f = [500; 400; 300; 350; 450]; % 万元
c = rand(num_sites, num_customers) * 10; % 随机生成运输成本
cap = [800; 600; 500; 550; 700]; % 千件
d = randi([20, 100], 1, num_customers); % 随机生成客户需求
% 目标函数:总成本 = 固定成本 + 运输成本
objective = f' * y + sum(sum(c .* x));
% 约束条件
constraints = [];
% 1. 每个客户的需求必须被满足
for j = 1:num_customers
constraints = [constraints, sum(x(:, j)) == d(j)];
end
% 2. 从仓库i发出的货物总量不能超过其容量,且只有建仓了才能发货
for i = 1:num_sites
constraints = [constraints, sum(x(i, :)) <= cap(i) * y(i)];
end
% 3. 至多建3个仓库
constraints = [constraints, sum(y) <= 3];
% 4. 非负约束
constraints = [constraints, x >= 0];
注意:约束
sum(x(i, :)) <= cap(i) * y(i)是建模的精髓。当y(i)=0(不建仓)时,不等式右边为0,强制x(i, :)=0,即该仓库不能发货。当y(i)=1时,约束变为正常的容量限制。这种用0-1变量激活或禁用一组连续变量约束的技巧,是离散优化中的基础且重要的模式。
最后,调用求解器求解。这里我们以Gurobi为例:
% 设置求解器为Gurobi
ops = sdpsettings('solver', 'gurobi', 'verbose', 1);
% 求解最小化问题
diagnostics = optimize(constraints, objective, ops);
if diagnostics.problem == 0
disp('求解成功!');
optimal_y = value(y);
optimal_x = value(x);
optimal_cost = value(objective);
fprintf('最优建仓方案(1为建,0为不建): %s\n', mat2str(optimal_y'));
fprintf('最小总成本: %.2f 万元\n', optimal_cost);
else
disp('求解失败,请检查模型或参数。');
end
这个案例清晰地展示了binvar如何将“建或不建”的离散决策嵌入到线性规划框架中。通过y变量,我们优雅地控制了与之关联的连续决策x的有效性


603

被折叠的 条评论
为什么被折叠?



