CPLEX OPL中如何定义含i<j或i≠j下标的决策变量xijk
嘿,作为一个经常和OPL打交道的老玩家,我太懂你这种冗余变量的烦恼了!其实用OPL的集合功能就能完美解决这个问题,下面给你两种常见场景的方案:
方案1:仅保留i < j的变量(最常用,适合顺序建模)
因为你的x[i][j][k]是表示工件i和j在机器k上的加工顺序,其实只需要存i < j的情况就够了——比如x[<i,j>][k] = 1就代表i在j前面加工,0就代表j在i前面,完全不需要重复定义x[<j,i>][k],这样直接砍掉一半冗余变量!
具体代码这么写:
int jobsNum = ...; int machinesNum = ...; range jobs = 0..jobsNum-1; range machines = 0..machinesNum-1; // 先定义所有满足i < j的工件对集合 {tuple(int i, int j)} jobPairs = {<i,j> | i,j in jobs : i < j}; // 基于这个集合定义决策变量,只生成需要的xijk dvar boolean x[jobPairs][machines];
之后写约束的时候,直接遍历jobPairs就行,比如要表示机器k上任意两个工件有且只有一种顺序,就不用再写x[i][j][k] + x[j][i][k] = 1,而是直接用x[<i,j>][k]的0/1值来对应两种情况,简洁又高效。
方案2:保留i ≠ j的变量(特殊场景用)
如果你的业务逻辑确实需要区分所有i≠j的情况(比如某些双向约束场景),那也可以定义排除i=j的集合:
{tuple(int i, int j)} jobPairs = {<i,j> | i,j in jobs : i != j}; dvar boolean x[jobPairs][machines];
这种写法会去掉所有i=j的无用变量,但保留i<j和j<i的对,适合确实需要双向变量的场景。
为什么这么做?
这样定义的核心是用OPL的集合过滤功能,提前把无效的下标排除在外,从根源上减少决策变量的数量——尤其是当工件数很多的时候,变量数的减少会大幅提升求解器的运行速度,避免冗余计算。
内容的提问来源于stack exchange,提问作者Li Danyuan
相关产品推荐
相关产品推荐

