You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

两阶段取送车辆路径问题CPLEX代码结构优化咨询

两阶段取送车辆路径问题CPLEX代码优化方案

一、优化后的代码结构

集合定义(简化命名+合并逻辑)

{string} Depots = ...;
{string} Satellites = ...;
{string} Customers = ...;
{string} AllNodes = Depots union Satellites union Customers; 
{string} Tier1Nodes = Depots union Satellites; // 第一梯队节点:仓库+卫星点
{string} Tier2Nodes = Satellites union Customers; // 第二梯队节点:卫星点+客户

参数定义(统一命名风格)

float distance[AllNodes][AllNodes] = ...;   // 全节点距离矩阵,仓库-客户直接连接成本高                      
float deliveryDemand[Customers] = ...; // 客户配送需求
float pickupDemand[Customers] = ...; // 客户取货需求
float satelliteCapacity[Satellites] = ...; // 卫星点容量
float bigVehicleCapacity = ...; // 第一梯队车辆容量
float smallVehicleCapacity = ...; // 第二梯队车辆容量

决策变量(分组+语义化命名)

// 路径弧变量
dvar boolean tier1Arc[Tier1Nodes][Tier1Nodes]; // 第一梯队路径弧
dvar boolean tier2Arc[Tier2Nodes][Tier2Nodes]; // 第二梯队路径弧
dvar boolean customerToSat[Customers][Satellites]; // 客户-卫星点分配关系

// 卫星点需求变量
dvar float+ satelliteDelivery[Satellites]; // 卫星点总配送需求
dvar float+ satellitePickup[Satellites]; // 卫星点总取货需求

// 车辆载货量辅助变量
dvar float+ tier1DeliverLoadBefore[Satellites]; // 第一梯队服务卫星点前配送载货量
dvar float+ tier1PickupLoadAfter[Satellites]; // 第一梯队服务卫星点后取货载货量
dvar float+ tier2DeliverLoadBefore[Customers]; // 第二梯队服务客户前配送载货量
dvar float+ tier2PickupLoadAfter[Customers]; // 第二梯队服务客户后取货载货量

目标函数(保持简洁)

// 最小化总运输成本
minimize sum(i,j in Tier1Nodes) distance[i][j] * tier1Arc[i][j] 
        + sum(l,m in Tier2Nodes) distance[l][m] * tier2Arc[l][m];

约束条件(分组+简化重复逻辑)

subject to {
  // -------------------------- 第一梯队路径约束 --------------------------
  // 卫星点必访问一次
  forall(s in Satellites){
    sum(j in Tier1Nodes: j != s) tier1Arc[s][j] == 1; 
  }    
  // 流量平衡
  forall(n in Tier1Nodes){
    sum(j in Tier1Nodes) tier1Arc[n][j] == sum(j in Tier1Nodes) tier1Arc[j][n];
  } 
  // 配送子路径消除
  forall(i,j in Satellites){
    tier1DeliverLoadBefore[j] - tier1DeliverLoadBefore[i] + bigVehicleCapacity * tier1Arc[i][j] 
    <= bigVehicleCapacity - satelliteDelivery[i];
  } 
  // 第一梯队配送载货量上下界
  forall(s in Satellites){
    satelliteDelivery[s] <= tier1DeliverLoadBefore[s] 
    && tier1DeliverLoadBefore[s] <= bigVehicleCapacity;
  }        
  // 取货子路径消除
  forall(i,j in Satellites){
    tier1PickupLoadAfter[i] - tier1PickupLoadAfter[j] + bigVehicleCapacity * tier1Arc[i][j] 
    <= bigVehicleCapacity - satellitePickup[j];
  }    
  // 第一梯队取货载货量上下界  
  forall(s in Satellites){
    satellitePickup[s] <= tier1PickupLoadAfter[s] 
    && tier1PickupLoadAfter[s] <= bigVehicleCapacity;
  }  
  // 第一梯队车辆总载货量限制
  forall(s in Satellites){
    tier1DeliverLoadBefore[s] + tier1PickupLoadAfter[s] - satelliteDelivery[s] <= bigVehicleCapacity;
  }   
  // -------------------------- 卫星点容量与需求约束 --------------------------
  // 卫星点总需求不超容量
  forall(s in Satellites){
    satelliteDelivery[s] + satellitePickup[s] <= satelliteCapacity[s];
  } 
  // 卫星点取货需求等于分配客户的取货总和
  forall(s in Satellites){
    sum(c in Customers) customerToSat[c][s] * pickupDemand[c] == satellitePickup[s];
  }        
  // 卫星点配送需求等于分配客户的配送总和
  forall(s in Satellites){
    sum(c in Customers) customerToSat[c][s] * deliveryDemand[c] == satelliteDelivery[s];
  }  
  // -------------------------- 第二梯队路径约束 --------------------------
  // 客户必访问一次
  forall(c in Customers){
    sum(m in Tier2Nodes: m != c) tier2Arc[c][m] == 1;
  }   
  // 流量平衡
  forall(n in Tier2Nodes){
    sum(m in Tier2Nodes) tier2Arc[n][m] == sum(m in Tier2Nodes) tier2Arc[m][n];
  }  
  // -------------------------- 客户-卫星点分配约束 --------------------------
  // 每个客户仅分配至一个卫星点
  forall(c in Customers){
    sum(s in Satellites) customerToSat[c][s] == 1;
  }  
  // 非法路径规避:客户-卫星点弧仅在分配关系存在时允许
  forall(s in Satellites, c in Customers){
    tier2Arc[c][s] <= customerToSat[c][s]; // 客户到卫星点
    tier2Arc[s][c] <= customerToSat[c][s]; // 卫星点到客户
  }
  // 客户路径必须归属同一卫星点
  forall(c1,c2 in Customers: c1 != c2, s in Satellites){
    tier2Arc[c1][c2] + customerToSat[c1][s] + sum(s2 in Satellites: s2 != s) customerToSat[c2][s2] <= 2;
  }  
  // -------------------------- 第二梯队载货量约束 --------------------------
  // 配送子路径消除
  forall(c1,c2 in Customers){
    tier2DeliverLoadBefore[c2] - tier2DeliverLoadBefore[c1] + smallVehicleCapacity * tier2Arc[c1][c2] 
    + (smallVehicleCapacity - deliveryDemand[c1] - deliveryDemand[c2]) * tier2Arc[c2][c1] 
    <= smallVehicleCapacity - deliveryDemand[c1];
  }
  // 第二梯队配送载货量下界
  forall(c in Customers){
    sum(m in Customers) tier2Arc[c][m] * deliveryDemand[m] + deliveryDemand[c] <= tier2DeliverLoadBefore[c];
  }
  // 第二梯队配送载货量上界
  forall(s in Satellites, c in Customers){
    tier2DeliverLoadBefore[c] <= smallVehicleCapacity - (smallVehicleCapacity - deliveryDemand[c]) * tier2Arc[c][s];
  }    
  // 取货子路径消除
  forall(c1,c2 in Customers){
    tier2PickupLoadAfter[c1] - tier2PickupLoadAfter[c2] + smallVehicleCapacity * tier2Arc[c1][c2] 
    + (smallVehicleCapacity - pickupDemand[c1] - pickupDemand[c2]) * tier2Arc[c2][c1] 
    <= smallVehicleCapacity - pickupDemand[c2];
  }  
  // 第二梯队取货载货量下界
  forall(c in Customers){
    sum(m in Customers) tier2Arc[m][c] * pickupDemand[m] + pickupDemand[c] <= tier2PickupLoadAfter[c]; 
  }  
  // 第二梯队取货载货量上界
  forall(s in Satellites, c in Customers){
    tier2PickupLoadAfter[c] <= smallVehicleCapacity - (smallVehicleCapacity - pickupDemand[c]) * tier2Arc[s][c];
  }  
  // 第二梯队车辆总载货量限制
  forall(c in Customers){
    tier2DeliverLoadBefore[c] + tier2PickupLoadAfter[c] - deliveryDemand[c] <= smallVehicleCapacity;
  }
}

二、核心优化点说明

1. 集合与命名优化

  • 用语义化命名替代原有的模糊命名,比如Tier1Nodes、tier1Arc,直接体现变量功能,提升代码可读性
  • 集合定义保留必要的合并逻辑,同时通过命名明确各集合的覆盖范围,避免歧义

2. 代码结构模块化

  • 将约束按功能分组(第一梯队、卫星点、第二梯队、分配关系、载货量),用注释分隔,便于后续维护和调试
  • 合并嵌套循环:比如原约束15、16的双重循环合并为单个forall循环,简化代码结构的同时保持逻辑不变

3. 决策变量精简

  • 对辅助变量按功能分组命名,明确区分不同梯队的载货量变量,避免混淆
  • 在保留必要变量的前提下,去掉冗余的命名重复,提升代码简洁性

4. 约束逻辑简化

  • 合并重复的约束结构,比如客户-卫星点的双向弧约束,用一次循环处理两种方向的弧限制
  • 调整代码排版,让约束逻辑更直观,降低理解成本

内容的提问来源于stack exchange,提问作者Felix Miller

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.21 03:32:02