CPLEX中有向图基于节点子集的弧初始化及约束实现问题
问题解决方案
一、Excel读取出弧集合实现
你可以通过CPLEX OPL的SheetConnection接口直接读取Excel中的弧数据,按如下步骤实现:
- 先准备Excel表格,将所有弧按「起点、终点」两列存储,比如Sheet命名为
Arcs,A列存起点,B列存终点。 - 在OPL的.mod文件中定义相关集合:
// 节点子集定义 {int} Subset1= {44,99}; {int} Subset2={123456,123457,123458}; {int} Subset3={1,2,3,4,5,6,7,8,9,10,11,12,13,14,15}; {int} Nodes=Subset1 union Subset2 union Subset3; // 定义弧元组、全量弧集合、按起点索引的出弧终点集合 tuple Arc { int orig; int dest; } {Arc} AllArcs = ...; {int} destPerOrig[o in Nodes] = {a.dest | a in AllArcs : a.orig == o};
- 在同目录的.dat文件中配置Excel连接:
SheetConnection sheetData("你的Excel文件实际路径.xlsx"); AllArcs from SheetRead(sheetData, "Arcs!A2:B"); // 从第二行开始读取,跳过表头行
读取完成后destPerOrig会自动匹配每个节点的出弧终点,无出弧的节点对应空集合,无需手动录入。
二、约束报错问题修复
你的报错主要来自两个核心问题,按如下规则修改即可:
- 索引重复定义:第三个约束的sum项里重复声明了变量
i,OPL不允许同作用域下出现同名索引。 - 索引范围不匹配:你当前的
destPerOrig存储的是出弧终点,而第三个约束需要遍历指向节点i的所有入弧起点,两者维度不匹配。
修改后的约束代码如下:
{int} TEST= {99}; // 先确保决策变量x的索引范围是合法弧,示例定义参考: // dvar float+ x[AllArcs]; subject to { sum(m in M, j in a[m])x[<44,j>] == 3; sum(j in destPerOrig[99], t in TEST)x[<j,t>] == 3; forall(i in Nodes_wo_Subset1) // 遍历所有指向i的起点j,去掉重复的i声明 sum(j in {a.orig | a in AllArcs : a.dest == i}) x[<j,i>] == 1; }
如果要简化写法避免索引错误,可以提前预定义两个辅助集合:
// 按终点索引的入弧起点集合 {int} origPerDest[d in Nodes] = {a.orig | a in AllArcs : a.dest == d}; // 按起点索引的出弧元组集合 {Arc} outArcs[o in Nodes] = {a | a in AllArcs : a.orig == o};
之后第三个约束可以直接简化为:
forall(i in Nodes_wo_Subset1) sum(j in origPerDest[i]) x[<j,i>] == 1;
涉及出弧求和的逻辑也可以直接按弧遍历,比如sum(a in outArcs[44])x[a],不需要手动拼接<起点,终点>索引,能大幅降低索引越界的报错概率。
内容的提问来源于stack exchange,提问作者A321
相关产品推荐
相关产品推荐

