基于CPLEX与C++建模:如何线性化两个连续变量的乘积?
线性化[0,1]连续变量乘积x*y的方法(附CPLEX/C++实现)
我之前用CPLEX做数学建模时刚好处理过完全相同的场景,针对你这种两个0 ≤ x ≤ 1、0 ≤ y ≤ 1的连续变量乘积x*y,最直接且高效的线性化方式是引入辅助变量,再添加一组线性约束来等价替代乘积项,下面给你详细拆解:
核心思路:引入辅助变量z = x*y
我们可以定义一个新的连续变量z,让它等价于x*y,然后通过以下4个线性约束来确保z和x*y的行为完全一致:
z ≤ x:保证z不会超过x的取值(因为y≤1,所以x*y ≤x)z ≤ y:同理,保证z不会超过y的取值(x≤1,所以x*y ≤y)z ≥ x + y - 1:这是关键约束,当x和y都接近1时,它能保证z不会过小(比如x=0.9,y=0.9,那么z≥0.8,而x*y=0.81,刚好落在约束范围内)0 ≤ z ≤ 1:直接限定辅助变量的范围,和x、y保持一致
这组约束的优势在于,它完全刻画了x*y在[0,1]×[0,1]区间上的凸包,不会引入额外的松弛,CPLEX求解时能得到和原问题一致的最优解。
CPLEX/C++代码实现示例
假设你已经初始化了CPLEX的环境和模型,下面是具体的代码片段:
#include <ilcplex/ilocplex.h> int main() { IloEnv env; try { IloModel model(env); // 定义原始连续变量x和y,范围[0,1] IloNumVar x(env, 0.0, 1.0, ILOFLOAT, "x"); IloNumVar y(env, 0.0, 1.0, ILOFLOAT, "y"); // 引入辅助变量z,用于替代x*y,范围[0,1] IloNumVar z(env, 0.0, 1.0, ILOFLOAT, "z"); // 添加线性化约束 model.add(z <= x); model.add(z <= y); model.add(z >= x + y - 1.0); // 替换目标函数中的x*y为z(示例:假设目标是最大化x*y + 2x + 3y) IloObjective obj(env, z + 2*x + 3*y, IloObjective::Maximize); model.add(obj); // 求解模型(省略求解和结果输出的代码) IloCplex cplex(model); if (cplex.solve()) { std::cout << "最优解:x=" << cplex.getValue(x) << ", y=" << cplex.getValue(y) << ", z=x*y=" << cplex.getValue(z) << std::endl; } } catch (IloException& e) { std::cerr << "CPLEX异常:" << e << std::endl; } env.end(); return 0; }
额外注意事项
- 这个方法仅适用于x和y都在[0,1]区间的场景,如果变量范围更大,需要调整约束(比如当x∈[a,b],y∈[c,d]时,约束形式会更复杂)
- 如果你要处理多个变量乘积的情况,需要逐个拆解,或者考虑其他线性化技巧,但两个变量的场景用上面的方法足够高效
内容的提问来源于stack exchange,提问作者Ernando Gomes
相关产品推荐
相关产品推荐

