• 【CPLEX教程03】java调用cplex求解一个TSP问题模型


    00 前言

    前面我们已经搭建好cplex的java环境了,相信大家已经跃跃欲试,想动手写几个模型了。今天就来拿一个TSP的问题模型来给大家演示一下吧~

    CPLEX系列教程可以关注我们的公众号哦!获取更多精彩消息!

    01 TSP建模

    关于TSP建模,就不多解释了。以及什么是TSP问题,也不要问我了。直接贴一个现成的模型出来吧。

    02 程序框架

    整个程序框架如图,app下是调用cplex的主要package。


    其中:

    • App.java:程序入口,cplex调用建模求解过程。
    • ConstraintFactory.java:控制子环约束的。
    • FileManager.java:读取instance数据的。

    package graph定义了一些变量,在求解过程中需要用到。input是算例,包含100-9000个城市。

    03 求解过程

    求解过程可以分为以下几步进行:

    1. 定义一个模型
    IloCplex model = new IloCplex();
    
    1. 定义决策变量,boolVar可以返回一个01的bool类型决策变量。
    // define variables
    IloIntVar[][] x = new IloIntVar[data.size()][data.size()];
    for (int i = 0; i < x.length; i++) {
    	for (int j = 0; j < x.length; j++) {
    		x[i][j] = model.boolVar("X[" + i + ", " + j + "]");
    	}
    }
    
    
    1. 添加约束7-1,addTerm将1*x[i][j]添加进表达式r里面,最终r的取值是里面所有的元素之和,也就是(1*x[i][1]+1*x[i][2]+...+1*x[i][n])
    // one has only a city to go, and should
    for (int i = 0; i < x.length; i++) {
    	IloLinearIntExpr r = model.linearIntExpr();
    	for (int j = 0; j < x.length; j++) {
    //						if (i == j)
    //							continue;
    		r.addTerm(1, x[i][j]);
    	}
    	model.addEq(r, 1);
    }
    
    
    1. 添加约束7-2,原理同上一条。
    // one can only arrive to one city at a time, and should
    for (int j = 0; j < x.length; j++) {
    	IloLinearIntExpr r = model.linearIntExpr();
    	for (int i = 0; i < x.length; i++) {
    //						if (i == j)
    //							continue;
    		r.addTerm(1, x[i][j]);
    	}
    	model.addEq(r, 1);
    }
    
    
    1. 添加约束7-3,子环约束处理有点复杂,但这个不是本文重点,读者自行理解。
    // add cycle restrictions
    for (Stack<Edge> stack : stacks) {
    //					stack.forEach((edge) -> System.out.println(edge.getFrom() + "->" + edge.getTo()));
    	constraintFactory.cycleRestrictions(model, x, stack);
    }
    
    1. 添加目标函数,z的表达式同上。
    // one should complete the tour within the smallest distance possible
    IloLinearNumExpr z = model.linearNumExpr();
    for (int i = 0; i < x.length; i++) {
    	for (int j = 0; j < x.length; j++) {
    		if (i == j)
    			continue;
    		z.addTerm(distance[i][j], x[i][j]);
    	}
    }
    
    
    1. 确定目标是最小化目标
    model.addMinimize(z);
    
    1. 开始求解
    if (model.solve()) {
    
    	// get tour
    	for (int i = 0; i < x.length; i++) {
    		for (int j = 0; j < x.length; j++) {
    			if (model.getValue(x[i][j]) >= 0.5) {
    				tour.add(new Edge(i, j));
    			}
    		}
    	}
    
    	// repaint tour
    } else {
    	System.err.println("Boi, u sick!");
    	System.exit(1);
    }
    

    注意,一次求解不一定能求得最优解,小编跑了一个早上都跑不出来,还是100个节点的。model.getValue(x[i][j]) >= 0.5这个判断只是把求解过程中一些较好的边给添加进去而已。最优解是要满足所有约束的。

    04 运行说明

    代码下载请关注我们的公众号哦!后台回复【CPTSP】不包括【】即可下载。

    代码来源GitHub,小编去掉了部分代码。期待后期进一步精简和修改,大家下载下来后用eclipse导入,设置好cplex环境以后。在App.java里面,右键Run As->Run configurations...:

    找到App,在Arguments窗口,找到Program arguments:

    输入参数说明:
    --instancePath+空格+算例文件的路径,注意用英文双引号括起来。
    --maximumRead+空格+数字,表示算例大小,也就是多少个城市,文件名可以直接看出。

    然后就可以愉快的run了。

    附上运行结果:

    大家可以在while(count<1)这个条件里面更改迭代次数,以便能获取更好的解。

  • 相关阅读:
    [leetCode]09.用两个栈实现队列
    ubuntu:无法获得锁;无法锁定管理目录
    [leetCode]07.重建二叉树
    [leetCode]剑指 Offer 06. 从尾到头打印链表
    [leetCode]剑指 Offer 05. 替换空格
    [leetCode]1330.翻转子数组得到最大的数组值
    [leetCode]312.戳气球
    UVALive
    CodeChef
    CodeChef
  • 原文地址:https://www.cnblogs.com/dengfaheng/p/11162150.html
Copyright © 2020-2023  润新知