问题定义:
VRPTW,即带时间窗约束的车辆路径问题,是在经典的VRP问题上加入了一个时间窗约束。
数学模型:


求解:
代码结构:

其中Data类表示定义参数,读取数据和初始化参数

package com.chb;import java.io.BufferedReader;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.util.Scanner;public class Data {public static int pointnum=102;public static int carnum;public static int cap;public static double E;public static double L;public static int point[][]=new int[pointnum][2];public static int s[]=new int[pointnum];public static double a[]=new double[pointnum];public static double b[]=new double[pointnum];public static int demand[]=new int[pointnum];public static int car[]=new int[pointnum];public static double dist[][]=new double[pointnum][pointnum];public static double arcs[][]=new double[pointnum][pointnum];//截断小数3.26434-->3.2public static double double_truncate(double v){int iv = (int) v;if(iv+1 - v <= 0.000000000001)return iv+1;double dv = (v - iv) * 10;int idv = (int) dv;double rv = iv + idv / 10.0;return rv;}//读取数据并且初始化参数public static void read_data(String path,Data data) throws Exception {String line=null;String substr[]=null;Scanner cin=new Scanner(new BufferedReader(new FileReader(path)));for (int i = 0; i < 4; i++) {line=cin.nextLine();}line=cin.nextLine();line.trim();substr=line.split("\\s+");carnum=Integer.parseInt(substr[1]);cap=Integer.parseInt(substr[2]);for (int i = 0; i < 4; i++) {line=cin.nextLine();}for (int i = 0; i < pointnum-1; i++) {line=cin.nextLine();line.trim();substr=line.split("\\s+");point[i][0]=Integer.parseInt(substr[2]);point[i][1]=Integer.parseInt(substr[3]);demand[i]=Integer.parseInt(substr[4]);a[i]=Integer.parseInt(substr[5]);b[i]=Integer.parseInt(substr[6]);s[i]=Integer.parseInt(substr[7]);}cin.close();//终点数据初始化point[pointnum-1]=point[0];demand[pointnum-1]=demand[0];a[pointnum-1]=a[0];b[pointnum-1]=b[0];s[pointnum-1]=s[0];E=a[0];L=b[0];double min1=1e15;double min2=1e15;//距离矩阵初始化for (int i = 0; i < pointnum; i++) {for (int j = 0; j < pointnum; j++) {if(i==j) {dist[i][j]=0;continue;}else {dist[i][j]=Math.sqrt(Math.pow(point[i][0]-point[j][0], 2)+Math.pow(point[i][1]-point[j][1], 2));dist[i][j]=double_truncate(dist[i][j]);}}}dist[pointnum-1][0]=0;dist[0][pointnum-1]=0;//距离矩阵满足三角关系for (int k = 0; k < pointnum; k++) {for (int i = 0; i < pointnum; i++) {for (int j = 0; j < pointnum; j++) {if(dist[i][j]>dist[i][k]+dist[k][j]) {dist[i][j]=dist[i][k]+dist[k][j];}}}}//初始化为完全图for (int i = 0; i <  pointnum; i++) {for (int j = 0; j <  pointnum; j++) {if(i==j) {arcs[i][j]=0;}else {arcs[i][j]=1;}}}//除去不符合时间窗和容量约束的边for (int i = 0; i < pointnum; i++) {for (int j = 0; j < pointnum; j++) {if(i==j) {continue;}if(a[i]+s[i]+dist[i][j]>b[j]||demand[i]+demand[j]>cap) {arcs[i][j]=0;}if(a[0]+s[i]+dist[0][i]+dist[i][pointnum-1]>b[pointnum-1]) {System.out.println("计算错误");}}}for (int i = 1; i < pointnum-1; i++) {if(b[i]-dist[0][i]<min1) {min1=b[i]-dist[0][i];}if(a[i]+s[i]+dist[i][pointnum-1]<min2) {min2=a[i]+s[i]+dist[i][pointnum-1];}}if(E>min1||L<min2) {System.out.println("计算错误");System.exit(0);}//初始化配送中心0,n+1的arcsarcs[pointnum-1][0]=0;arcs[0][pointnum-1]=1;for (int i = 1; i < pointnum-1; i++) {arcs[pointnum-1][i]=0;arcs[i][0]=1;}}}

Solution类是对解的可行性进行判断

package com.chb;import java.util.ArrayList;
import ilog.concert.IloException;public class Solution {double epsilon = 0.0001;Data data = new Data();ArrayList<ArrayList<Integer>> routes = new ArrayList<>();ArrayList<ArrayList<Double>> servetimes = new ArrayList<>();public Solution(Data data, ArrayList<ArrayList<Integer>> routes, ArrayList<ArrayList<Double>> servetimes) {super();this.data = data;this.routes = routes;this.servetimes = servetimes;}//函数功能:比较两个数的大小public int double_compare(double v1,double v2) {if (v1 < v2 - epsilon) {return -1;}if (v1 > v2 + epsilon) {return 1;}return 0;}//函数功能:解的可行性判断public void fesible() throws IloException {//车辆数量可行性判断if (routes.size() > data.carnum) {System.out.println("error: carnum!!!");System.exit(0);}//车辆载荷可行性判断for (int k = 0; k < routes.size(); k++) {ArrayList<Integer> route = routes.get(k);double capasity = 0;for (int i = 0; i < route.size(); i++) {capasity += data.demand[route.get(i)];}if (capasity > data.cap) {System.out.println("error: cap!!!");System.exit(0);}}//时间窗、车容量可行性判断for (int k = 0; k < routes.size(); k++) {ArrayList<Integer> route = routes.get(k);ArrayList<Double> servertime = servetimes.get(k);double capasity = 0;for (int i = 0; i < route.size()-1; i++) {int origin = route.get(i);int destination = route.get(i+1);double si = servertime.get(i);double sj = servertime.get(i+1);if (si < data.a[origin] && si >  data.b[origin]) {System.out.println("error: servertime!");System.exit(0);}if (double_compare(si + data.dist[origin][destination],data.b[destination]) > 0) {System.out.println(origin + ": [" + data.a[origin] + ","+data.b[origin]+"]"+ " "+ si);System.out.println(destination + ": [" + data.a[destination] + ","+data.b[destination]+"]"+ " "+ sj);System.out.println(data.dist[origin][destination]);System.out.println(destination + ":" );System.out.println("error: forward servertime!");System.exit(0);}if (double_compare(sj - data.dist[origin][destination],data.a[origin]) < 0) {System.out.println(origin + ": [" + data.a[origin] + ","+data.b[origin]+"]"+ " "+ si);System.out.println(destination + ": [" + data.a[destination] + ","+data.b[destination]+"]"+ " "+ sj);System.out.println(data.dist[origin][destination]);System.out.println(destination + ":" );System.out.println("error: backward servertime!");System.exit(0);}}if (capasity > data.cap) {System.out.println("error: cap!!!");System.exit(0);}}}
}

类 Vrptw 是建立模型并求解模型

package com.chb;import java.util.ArrayList;import ilog.concert.IloException;
import ilog.concert.IloNumExpr;
import ilog.concert.IloNumVar;
import ilog.concert.IloNumVarType;
import ilog.cplex.IloCplex;public class Vrptw {Data data;                   //定义类Data的对象IloCplex cplex;             //定义cplex内部类的对象     public IloNumVar[][][] x;   //x[i][j][k]表示弧arcs[i][j]被车辆k访问public IloNumVar[][] w;      //车辆访问所有点的时间矩阵double cost;              //目标值objectSolution solution;           public Vrptw(Data data) {this.data = data;}//函数功能:解模型,并生成车辆路径和得到目标值public void solve() throws IloException {ArrayList<ArrayList<Integer>> routes = new ArrayList<>();     //定义车辆路径链表ArrayList<ArrayList<Double>> servetimes = new ArrayList<>();   //定义花费时间链表//初始化车辆路径和花费时间链表,链表长度为车辆数kfor (int k = 0; k < data.carnum; k++) {ArrayList<Integer> r = new ArrayList<>();  //定义一个对象为int型的链表ArrayList<Double> t = new ArrayList<>();   //定义一个对象为double型的链表routes.add(r);                               //将上述定义的链表加入到链表routes中servetimes.add(t);                            //同上}//判断建立的模型是否可解if(cplex.solve() == false){//模型不可解System.out.println("problem should not solve false!!!");return;                                     //若不可解,则直接跳出solve函数}else{//模型可解,生成车辆路径for(int k = 0; k < data.carnum; k++){boolean terminate = true;int i = 0;routes.get(k).add(0);       servetimes.get(k).add(0.0);while(terminate){for (int j = 0; j < data.pointnum; j++) {if (data.arcs[i][j]>=0.5 && cplex.getValue(x[i][j][k])>=0.5) {routes.get(k).add(j);servetimes.get(k).add(cplex.getValue(w[j][k]));i = j;break;}}if (i == data.pointnum-1) {terminate = false;}}}}solution = new Solution(data,routes,servetimes);cost = cplex.getObjValue();System.out.println("routes="+solution.routes);}//函数功能:根据VRPTW数学模型建立VRPTW的cplex模型private void build_cplex() throws IloException {//modelcplex = new IloCplex();cplex.setOut(null);//variablesx = new IloNumVar[data.pointnum][data.pointnum][data.carnum];w = new IloNumVar[data.pointnum][data.carnum];              //车辆访问点的时间//定义cplex变量x和w的数据类型及取值范围for (int i = 0; i < data.pointnum; i++) {for (int k = 0; k < data.carnum; k++) {w[i][k] = cplex.numVar(0, 1e15, IloNumVarType.Float, "w" + i + "," + k);}for (int j = 0; j < data.pointnum; j++) {if (data.arcs[i][j]==0) {x[i][j] = null;}else{//Xijk,公式(10)-(11)for (int k = 0; k < data.carnum; k++) {x[i][j][k] = cplex.numVar(0, 1, IloNumVarType.Int, "x" + i + "," + j + "," + k);}}}}//加入目标函数//公式(1)IloNumExpr obj = cplex.numExpr();for(int i = 0; i < data.pointnum; i++){for(int j = 0; j < data.pointnum; j++){if (data.arcs[i][j]==0) {continue;}for(int k = 0; k < data.carnum; k++){obj = cplex.sum(obj, cplex.prod(data.dist[i][j], x[i][j][k]));}}}cplex.addMinimize(obj);//加入约束//公式(2)for(int i= 1; i < data.pointnum-1;i++){IloNumExpr expr1 = cplex.numExpr();for (int k = 0; k < data.carnum; k++) {for (int j = 1; j < data.pointnum; j++) {if (data.arcs[i][j]==1) {expr1 = cplex.sum(expr1, x[i][j][k]);}}}cplex.addEq(expr1, 1);}//公式(3)for (int k = 0; k < data.carnum; k++) {IloNumExpr expr2 = cplex.numExpr();for (int j = 1; j < data.pointnum; j++) {if (data.arcs[0][j]==1) {expr2 = cplex.sum(expr2, x[0][j][k]);}}cplex.addEq(expr2, 1);}//公式(4)for (int k = 0; k < data.carnum; k++) {for (int j = 1; j < data.pointnum-1; j++) {IloNumExpr expr3 = cplex.numExpr();IloNumExpr subExpr1 = cplex.numExpr();IloNumExpr subExpr2 = cplex.numExpr();for (int i = 0; i < data.pointnum; i++) {if (data.arcs[i][j]==1) {subExpr1 = cplex.sum(subExpr1,x[i][j][k]);}if (data.arcs[j][i]==1) {subExpr2 = cplex.sum(subExpr2,x[j][i][k]);}}expr3 = cplex.sum(subExpr1,cplex.prod(-1, subExpr2));cplex.addEq(expr3, 0);}}//公式(5)for (int k = 0; k < data.carnum; k++) {IloNumExpr expr4 = cplex.numExpr();for (int i = 0; i < data.pointnum-1; i++) {if (data.arcs[i][data.pointnum-1]==1) {expr4 = cplex.sum(expr4,x[i][data.pointnum-1][k]);}}cplex.addEq(expr4, 1);}//公式(6)double M = 1e5;for (int k = 0; k < data.carnum; k++) {for (int i = 0; i < data.pointnum; i++) {for (int j = 0; j < data.pointnum; j++) {if (data.arcs[i][j] == 1) {IloNumExpr expr5 = cplex.numExpr();IloNumExpr expr6 = cplex.numExpr();expr5 = cplex.sum(w[i][k], data.s[i]+data.dist[i][j]);expr5 = cplex.sum(expr5,cplex.prod(-1, w[j][k]));expr6 = cplex.prod(M,cplex.sum(1,cplex.prod(-1, x[i][j][k])));cplex.addLe(expr5, expr6);}}}}//公式(7)for (int k = 0; k < data.carnum; k++) {for (int i = 1; i < data.pointnum-1; i++) {IloNumExpr expr7 = cplex.numExpr();for (int j = 0; j < data.pointnum; j++) {if (data.arcs[i][j] == 1) {expr7 = cplex.sum(expr7,x[i][j][k]);}}cplex.addLe(cplex.prod(data.a[i], expr7), w[i][k]);cplex.addLe(w[i][k], cplex.prod(data.b[i], expr7));}}//公式(8)for (int k = 0; k < data.carnum; k++) {cplex.addLe(data.E, w[0][k]);cplex.addLe(data.E, w[data.pointnum-1][k]);cplex.addLe(w[0][k], data.L);cplex.addLe(w[data.pointnum-1][k], data.L);}//公式(9)for (int k = 0; k < data.carnum; k++) {IloNumExpr expr8 = cplex.numExpr();for (int i = 1; i < data.pointnum-1; i++) {IloNumExpr expr9 = cplex.numExpr();for (int j = 0; j < data.pointnum; j++) {if (data.arcs[i][j] == 1) {expr9=cplex.sum(expr9,x[i][j][k]);}}expr8 = cplex.sum(expr8,cplex.prod(data.demand[i],expr9));}cplex.addLe(expr8, data.cap);}}public static void main(String[] args) throws Exception {Data data=new Data();String path="data/c102.txt";data.read_data(path, data);System.out.println("输入成功");System.out.println("程序执行中**************************");Vrptw cplex=new Vrptw(data);cplex.build_cplex();double cplex_time1=System.nanoTime();cplex.solve();cplex.solution.fesible();double cplex_time2=System.nanoTime();double cplex_time=( cplex_time2- cplex_time1)/1e9;System.out.println("cplex_time:"+cplex_time);System.out.println("bestcost:"+cplex.cost);}
}

Data文件夹中是测试数据
运行结果截图:

本文转载、提炼来源于:https://mp.weixin.qq.com/s/OdzX_b9sLJ2PZ4WoDM5NnQ

CPLEX-求解VRPTW模型相关推荐

  1. CPLEX-分支定界算法调用cplex求解VRPTW

    前面讲了Cplex直接求解VRPTW的模型,下面我们在分支定界算法中调用Cplex来求解VRPTW 1.分支定界算法 (1)定义: (2)求解过程: 1)确定一个下界(初始解LB),上界定为无穷大UB ...

  2. 【路径规划】基于粒子群算法求解VRPTW模型

    1 粒子群算法 1.1 研究背景 粒子群算法的发展过程.粒子群优化算法(Partical Swarm Optimization PSO),粒子群中的每一个粒子都代表一个问题的可能解,通过粒子个体的简单 ...

  3. 使用Cplex求解均值方差模型

       在进行多目标进化算法求解投资组合问题时,由于多目标进化算法求得的是一组近似最优解,对于最大化收益和最小化风险的两目标M-V模型,需要找到一个基准,方便作为参考.这里利用Cplex工具求解均值-方 ...

  4. c++调用cplex求解例子_Java调用cplex求解运输问题

    Java调用cplex求解运输问题 本文中的课件来自清华大学深圳国际研究生院,物流与交通学部张灿荣教授<生产管理>课程. 运输问题(Transportation Problem)描述 运输 ...

  5. c++调用cplex求解例子_视频教程 | 用Python玩转运筹优化求解器IBM CPLEX(二)

    编者按 优化求解器对于做运筹学应用的学生来说,意义重大. 然而直到今天,放眼望去,全网(包括墙外)几乎没有一个系统的Cplex中文求解器教程. 作为华人运筹学的最大的社区,『运筹OR帷幄』 责无旁贷, ...

  6. python调用cplex求解装箱问题_装箱问题的CPLEX求解

    装箱问题(Bin Packing Problem) 装箱问题即搬家公司问题.一个搬家公司有无限多的箱子,每个箱子的承重上限为W,当搬家公司进入一个房间时,所有物品都必须被装入箱子,每个物品的重量为wi ...

  7. Java调用cplex求解运输问题

    Java调用cplex求解运输问题 Java调用cplex求解运输问题 运输问题(Transportation Problem)描述 运输问题的数学模型 Java调用cplex求解运输问题 trans ...

  8. Cplex求解考虑风光燃储综合能源系统鲁棒优化调度

    鲁棒优化的目的是求得这样一个解,对于可能出现的所有情况,约束条件均满足,并且使得最坏情况下的目标函数的函数值最优.综合能源系统鲁棒调度优化,以燃气轮机为核心,融合储能单元.考虑负荷侧需求以及风光出力侧 ...

  9. Yalmip使用学习 配置cplex求解器 实例

    yalmip学习 0. yalmip简介 0.1 什么是yalmip yalmip是由Lofberg开发的一种免费的优化求解工具,其最大特色在于集成许多外部的最优化求解器,形成一种统一的建模求解语言, ...

  10. 采用matlab编制含电气热的综合能源优化程序,采用yalmip和cplex求解,通过二阶锥模型实现相关约束限制

    电气热 综合能源 二阶锥 采用matlab编制含电气热的综合能源优化程序,采用yalmip和cplex求解,通过二阶锥模型实现相关约束限制,综合能源系统考虑39节点电网+6节点气网+热网模型,程序注释 ...

最新文章

  1. 【学习笔记】2、Python - Jupyter Notebook界面基础
  2. 【Socket】linux网络多路复用IO技术
  3. 好文推荐 | etcd 问题、调优、监控
  4. hibernate 环境搭建测试
  5. Java 基础【01】 This 用法
  6. paip.c++ 正则表达式的应用跟普通正则表达式的区别以及特别注意点总
  7. Sqoop 是什么?(二)
  8. java heapdump 分析工具_heapdump分析工具
  9. 大厂Java核心面试题出炉:java视频教程马士兵
  10. 在网页中插入背景音乐代码(html)
  11. 微信小程序中集成有赞UI自定义Tabbar组件
  12. 《Java编程那些事儿----这是一本书》
  13. [Python] 贡献度分析
  14. 灭火机器人C语言程序,- 一款基于STM32的智能灭火机器人设计
  15. java 生成pdf文件加密
  16. 如何使用bootstrap框架
  17. WinRAR捆绑木马
  18. 王峰十问Nervos联合创始人王宁宁:缘何“中国最懂以太坊的人”要走中国公链的自主创新之路?...
  19. 轻触开关的全球与中国市场2022-2028年:技术、参与者、趋势、市场规模及占有率研究报告
  20. Android中富文本用法包括点击事件处理

热门文章

  1. ubuntu20.04 搭建tftp服务器
  2. VB 源码 产生任意数之间随机数,支持负数
  3. 国内常见的14款低代码平台介绍
  4. 2021必看!java电子书合集
  5. java定义json数组_java json序列化自定义类,类数组
  6. java 项目开发流程_详解JAVA开发之JAVA项目开发的基本流程
  7. android切图双数,浅谈网页设计切图规范
  8. xcode中c语言清屏函数,浅谈iMac
  9. 计算机ip地址查询精确的位置,本机ip地址查询精确的位置 简单两步轻松搞定
  10. MySQL 递归查询下级