【运筹优化】贪心启发式算法和蜘蛛猴优化算法求解连续选址问题 + Java代码实现

文章目录

  • 一、问题描述
  • 二、思路分析
  • 三、解决方案
    • 3.1 贪心启发式算法
    • 3.2 群体智能算法(蜘蛛猴优化算法)
  • 四、总结


一、问题描述

选址问题是指在规划区域里选择一个或多个设施的位置,使得目标最优。

按照规划区域的结构划分,可以将选址问题分为:
1.连续选址问题:设施可以在给定范围的任意位置选址,设施的候选位置为无穷多。
2.离散选址问题:设施的候选位置是有限且较少的,实际中最常遇到这类问题。
3.网格选址问题:规划区域被划分为许多的小单元,每个设施占据其中有限个单元。

本博客将根据下面的例题,介绍连续选址问题的求解思路
(其中,问题1为运输问题,建议先阅读我的另一篇博客再来看本博客:【运筹优化】运输问题建模 + Java调用Cplex求解)

在这里插入图片描述


二、思路分析

问题(2)属于连续选址问题,它的数学模型和问题(1)的数学模型 Q 1 Q_1 Q1类似,唯一不同之处在于,问题(2)中, d i j d_{ij} dij也是一个决策变量。因此,它的数学模型是非线性的,无法直接通过Cplex直接求解。对于凸的无约束非线性模型,可以使用梯度下降法或牛顿法求出其最优解;对于其他非线性模型,通常使用启发式算法或群体智能算法寻求其较优解。由于不确定问题(2)模型是否为凸,因此本人采用了一个贪心启发式算法和一个群体智能算法(蜘蛛猴优化算法)对问题(2)进行求解。


三、解决方案

3.1 贪心启发式算法

首先介绍贪心启发式算法,为了更好地描述,给出下面的线性规划模型:

在这里插入图片描述
该模型的含义为:给定一个已知位置的料场和若干个工地的信息,确保将料场的储量全部运输到各个工地,并使得总运输成本最小。

然后介绍贪心启发式算法的基本思想:每次为一个料场 i i i定位置,基于每个工地的坐标和当前剩余需求量计算一个加权中心点作为当前料场 i i i的坐标,在确定了料场 i i i的位置之后,就可以将料场 i i i和当前工地的信息代入到线性的 Q 2 i Q^i_2 Q2i模型中调用Cplex进行求解,得到料场 i i i的最小成本的运输方案后,再更新每个工地的剩余需求量,然后以同样的步骤为下一个料场确定位置并更新工地信息,直到每个工地的位置都被确定。确定了每个工地的位置之后,再求解 Q 1 Q_1 Q1模型,即可得到当前料场坐标下最优的运输方案。

贪心启发式的Java代码实现如下:

public class Answer2 {/*** 料场对象*/@AllArgsConstructorstatic class Stockyard {/*** x,y坐标和储量c*/double x, y, c;}/*** 工地对象*/@AllArgsConstructorstatic class ConstructionSite {/*** x,y坐标和需求d*/double x, y, d;}private static double calcDistance(double x1, double y1, double x2, double y2) {return Math.sqrt(Math.pow(x1 - x2, 2) + Math.pow(y1 - y2, 2));}private static List<ConstructionSite> getInitConstructionSiteList() {List<ConstructionSite> constructionSiteList = new ArrayList<>();constructionSiteList.add(new ConstructionSite(1.25, 1.25, 3));constructionSiteList.add(new ConstructionSite(8.75, 0.75, 5));constructionSiteList.add(new ConstructionSite(0.5, 4.75, 4));constructionSiteList.add(new ConstructionSite(5.75, 5, 7));constructionSiteList.add(new ConstructionSite(3, 6.5, 6));constructionSiteList.add(new ConstructionSite(7.25, 7.75, 11));return constructionSiteList;}public static void main(String[] args) throws Exception {// 浮点型精度误差double EPS = 1e-06;// 料场列表List<Stockyard> stockyardList = new ArrayList<>();stockyardList.add(new Stockyard(0, 0, 20));stockyardList.add(new Stockyard(0, 0, 20));stockyardList.sort(new Comparator<Stockyard>() {@Overridepublic int compare(Stockyard o1, Stockyard o2) {return -Double.compare(o1.c, o2.c);}});// 工地列表List<ConstructionSite> constructionSiteList = getInitConstructionSiteList();// 初始化距离矩阵double[][] distanceMatrix = new double[stockyardList.size()][constructionSiteList.size()];// 开始循环for (int i = 0; i < stockyardList.size(); i++) {// 计算总需求量double totalDemand = constructionSiteList.stream().map(constructionSite -> {return constructionSite.d;}).reduce(0d, Double::sum);// 计算加权中心点作为料场i的坐标stockyardList.get(i).x = 0d;stockyardList.get(i).y = 0d;for (ConstructionSite constructionSite : constructionSiteList) {stockyardList.get(i).x += (constructionSite.x * constructionSite.d / totalDemand);stockyardList.get(i).y += (constructionSite.y * constructionSite.d / totalDemand);}// 计算距离矩阵for (int j = 0; j < distanceMatrix[i].length; j++) {distanceMatrix[i][j] = calcDistance(stockyardList.get(i).x, stockyardList.get(i).y, constructionSiteList.get(j).x, constructionSiteList.get(j).y);}if (totalDemand <= stockyardList.get(i).c) {break;}// 然后强制料场i必须送够c_i的量,并计算最小成本的运输方案// 开始建模IloCplex cplex = new IloCplex();// 声明变量IloNumVar[] x = new IloNumVar[constructionSiteList.size()];for (int j = 0; j < x.length; j++) {x[j] = cplex.numVar(0, constructionSiteList.get(j).d);}// 构造约束1:不能超出每个工地的需求for (int j = 0; j < constructionSiteList.size(); j++) {cplex.addLe(x[j], constructionSiteList.get(j).d);}// 构造约束2:料场中的储量必须全部送出cplex.addEq(cplex.sum(x), stockyardList.get(i).c);// 声明目标函数cplex.addMinimize(cplex.scalProd(x, distanceMatrix[i]));// 配置cplexcplex.setOut(null);cplex.setWarning(null);cplex.setParam(IloCplex.DoubleParam.EpOpt, EPS);// 开始求解if (cplex.solve()) {// 更新每个工地的需求量for (int j = 0; j < x.length; j++) {constructionSiteList.get(j).d -= cplex.getValue(x[j]);}} else {System.err.println("此题无解");}// 结束模型cplex.end();}for (int i = 0; i < stockyardList.size(); i++) {System.out.println("料场" + (i + 1) + "的坐标为: ( " + stockyardList.get(i).x + " , " + stockyardList.get(i).y + " )");}// 重新获取初始化的工地列表constructionSiteList = getInitConstructionSiteList();// 开始建模IloCplex cplex = new IloCplex();// 声明变量IloNumVar[][] x = new IloNumVar[stockyardList.size()][constructionSiteList.size()];for (int i = 0; i < x.length; i++) {for (int j = 0; j < x[i].length; j++) {x[i][j] = cplex.numVar(0, Math.min(stockyardList.get(i).c, constructionSiteList.get(j).d));}}// 构造约束1:必须满足每个工地的需求for (int j = 0; j < constructionSiteList.size(); j++) {IloLinearNumExpr expr = cplex.linearNumExpr();for (int i = 0; i < x.length; i++) {expr.addTerm(1, x[i][j]);}cplex.addEq(expr, constructionSiteList.get(j).d);}// 构造约束2:不能超过每个料场的储量for (int i = 0; i < stockyardList.size(); i++) {cplex.addLe(cplex.sum(x[i]), stockyardList.get(i).c);}// 声明目标函数IloLinearNumExpr target = cplex.linearNumExpr();for (int i = 0; i < x.length; i++) {for (int j = 0; j < x[i].length; j++) {target.addTerm(distanceMatrix[i][j], x[i][j]);}}cplex.addMinimize(target);// 配置cplexcplex.setOut(null);cplex.setWarning(null);cplex.setParam(IloCplex.DoubleParam.EpOpt, EPS);// 开始求解long s = System.currentTimeMillis();if (cplex.solve()) {System.out.println("最小吨千米数为: " + cplex.getObjValue());for (int i = 0; i < stockyardList.size(); i++) {for (int j = 0; j < x[i].length; j++) {double xValue = cplex.getValue(x[i][j]);if (xValue > EPS) {System.out.println("料场" + (i + 1) + "向工地" + (j + 1) + "运输" + xValue + "吨水泥");}}}System.out.println("求解用时: " + (System.currentTimeMillis() - s) / 1000d + " s");} else {System.err.println("此题无解");}// 结束模型cplex.end();}
}

运行结果如下:

料场1的坐标为: ( 5.208333333333333 , 5.159722222222222 )
料场2的坐标为: ( 4.90625 , 3.59375 )
最小吨千米数为: 114.45936860248577
料场1向工地4运输7.0吨水泥
料场1向工地5运输2.0吨水泥
料场1向工地6运输11.0吨水泥
料场2向工地1运输3.0吨水泥
料场2向工地2运输5.0吨水泥
料场2向工地3运输4.0吨水泥
料场2向工地5运输4.0吨水泥
求解用时: 0.0 s

3.2 群体智能算法(蜘蛛猴优化算法)

然后是使用了蜘蛛猴优化算法。每个蜘蛛猴的变量数组表示了每个料场的坐标。设置蜘蛛猴数量为50,迭代次数为60,局部领导者决策阶段的更新几率为0.1,局部领导者阶段的更新几率为0.8,最大组数为5,料场的坐标上下界分别为10和-10。

Java代码实现如下:

public class SMO_Solver {/*** 料场对象*/@AllArgsConstructorstatic class Stockyard {/*** x,y坐标和储量c*/double x, y, c;}/*** 工地对象*/@AllArgsConstructorstatic class ConstructionSite {/*** x,y坐标和需求d*/double x, y, d;}private double calcDistance(double x1, double y1, double x2, double y2) {return Math.sqrt(Math.pow(x1 - x2, 2) + Math.pow(y1 - y2, 2));}private static List<ConstructionSite> getInitConstructionSiteList() {List<ConstructionSite> constructionSiteList = new ArrayList<>();constructionSiteList.add(new ConstructionSite(1.25, 1.25, 3));constructionSiteList.add(new ConstructionSite(8.75, 0.75, 5));constructionSiteList.add(new ConstructionSite(0.5, 4.75, 4));constructionSiteList.add(new ConstructionSite(5.75, 5, 7));constructionSiteList.add(new ConstructionSite(3, 6.5, 6));constructionSiteList.add(new ConstructionSite(7.25, 7.75, 11));return constructionSiteList;}List<ConstructionSite> constructionSiteList;List<Stockyard> stockyardList;double EPS = 1e-06;public SMO_Solver(List<Stockyard> stockyardList, List<ConstructionSite> constructionSiteList) throws IloException {this.constructionSiteList = constructionSiteList;this.stockyardList = stockyardList;}// 蜘蛛猴对象class SpiderMonkey {// 当前蜘蛛猴坐标(自变量数组)double[] curVars;// 当前自变量对应的目标函数值double curObjValue;// 适应度(解决最小化问题,所以适应度为目标函数值的倒数)double fit;// 全参数构造public SpiderMonkey(double[] curVars, double curObjValue, double fit) {this.curVars = curVars;this.curObjValue = curObjValue;this.fit = fit;}}// 算法参数// 蜘蛛猴群List<SpiderMonkey[]> spiderMonkeyList = new ArrayList<>();// 局部领导者List<SpiderMonkey> localLeaderList = new ArrayList<>();// 最好的蜘蛛猴(全局领导者)SpiderMonkey bestSpiderMonkey;// 随机数对象Random random = new Random();// 最大迭代次数int maxGen = 60;// 蜘蛛猴数量int spiderMonkeyNum = 50;// 局部搜索次数(一般等于蜘蛛猴数量)int localSearchCount = spiderMonkeyNum;// 局部领导者决策阶段的更新几率double LLDP_PR = 0.1;// 局部领导者阶段的更新几率double LLP_PR = 0.8;// 变量维度数int varNum = 4;// 最大组数(一般要至少保证每组里有10个蜘蛛猴)int maxgroupNum = spiderMonkeyNum / 10;// 变量的上下界double[] ub = new double[]{10, 10, 10, 10};double[] lb = new double[]{-10, -10, -10, -10};// 局部计数器int[] localLimitCount = new int[]{0};// 停止条件int limitCnt = 30;// 全局计数器int globalLimitCount;// 记录迭代过程public double[][][] positionArr;// 记录迭代器的行数int curC = 0;// 是否开启贪心机制(只接受比当前解好的解)boolean greedy = true;// 求解主函数public void solve() {// 初始化蜘蛛猴种群initSpiderMonkeys();// 开始迭代for (int t = 0; t < maxGen; t++) {System.out.println(t + " : " + bestSpiderMonkey.curObjValue);// 局部领导者阶段(LLP:所有的蜘蛛猴都有机会更新自己)LLP();// 全局领导者阶段(GLP:轮盘赌,随机选取,偏向于对fit值大的蜘蛛猴进行更新)GLP();// 全局领导者学习阶段(如果全局领导者有更新,则globalLimitCount=0,否则globalLimitCount++)GLLP();// 局部领导者学习阶段(如果局部领导者有更新,则localLimitCount=0,否则localLimitCount++)LLLP();// 局部领导者决策阶段LLDP();// 全局领导者决策阶段GLDP();}// 输出最好的结果System.out.println("变量取值为:" + Arrays.toString(bestSpiderMonkey.curVars));System.out.println("最优解为:" + bestSpiderMonkey.curObjValue);}// 全局领导者决策阶段private void GLDP() {if (globalLimitCount >= limitCnt) {globalLimitCount = 0;if (spiderMonkeyList.size() < maxgroupNum) {// 分裂List<SpiderMonkey> tempList = new ArrayList<>();for (SpiderMonkey[] spiderMonkeys : spiderMonkeyList) {tempList.addAll(Arrays.asList(spiderMonkeys));}tempList.sort(new Comparator<SpiderMonkey>() {@Overridepublic int compare(SpiderMonkey o1, SpiderMonkey o2) {return Double.compare(o2.fit, o1.fit);}});//int groupNum = spiderMonkeyList.size() + 1;spiderMonkeyList = new ArrayList<>();int avgNum = spiderMonkeyNum / groupNum;for (int i = 0; i < groupNum - 1; i++) {SpiderMonkey[] spiderMonkeys = new SpiderMonkey[avgNum];for (int j = 0; j < avgNum; j++) {spiderMonkeys[j] = copySpiderMonkey(tempList.remove(0));}spiderMonkeyList.add(spiderMonkeys);}spiderMonkeyList.add(tempList.toArray(new SpiderMonkey[0]));localLimitCount = new int[groupNum];} else {// 融合SpiderMonkey[] spiderMonkeys = new SpiderMonkey[spiderMonkeyNum];int i = 0;for (SpiderMonkey[] monkeys : spiderMonkeyList) {for (SpiderMonkey monkey : monkeys) {spiderMonkeys[i++] = copySpiderMonkey(monkey);}}spiderMonkeyList = new ArrayList<>();spiderMonkeyList.add(spiderMonkeys);localLimitCount = new int[]{0};}// 更新局部领导者localLeaderList = new ArrayList<>();for (SpiderMonkey[] spiderMonkeys : spiderMonkeyList) {localLeaderList.add(copySpiderMonkey(spiderMonkeys[0]));int index = localLeaderList.size() - 1;for (int i = 1; i < spiderMonkeys.length; i++) {if (localLeaderList.get(index).fit < spiderMonkeys[i].fit) {localLeaderList.set(index, copySpiderMonkey(spiderMonkeys[i]));}}}}}// 局部领导者决策阶段private void LLDP() {int c = 0;for (int i = 0; i < spiderMonkeyList.size(); i++) {SpiderMonkey[] spiderMonkeys = spiderMonkeyList.get(i);if (localLimitCount[i] < limitCnt) {for (int j = 0; j < spiderMonkeys.length; j++) {SpiderMonkey tempSpiderMonkey = copySpiderMonkey(spiderMonkeys[j]);for (int m = 0; m < varNum; m++) {if (random.nextDouble() <= LLDP_PR) {tempSpiderMonkey.curVars[m] = lb[m] + random.nextDouble() * (ub[m] - lb[m]);} else {double moveDist = random.nextDouble() * (bestSpiderMonkey.curVars[m] - tempSpiderMonkey.curVars[m]) + random.nextDouble() * (spiderMonkeys[random.nextInt(spiderMonkeys.length)].curVars[m] - tempSpiderMonkey.curVars[m]);moveSpiderMonkey(tempSpiderMonkey, m, moveDist);}}tempSpiderMonkey.curObjValue = getObjValue(tempSpiderMonkey.curVars);tempSpiderMonkey.fit = 1 / tempSpiderMonkey.curObjValue;if (greedy) {if (tempSpiderMonkey.fit > spiderMonkeys[j].fit) {spiderMonkeys[j] = tempSpiderMonkey;}} else {spiderMonkeys[j] = tempSpiderMonkey;}}}for (int j = 0; j < spiderMonkeys.length; j++) {for (int m = 0; m < spiderMonkeys[j].curVars.length; m++) {positionArr[curC][c][m] = spiderMonkeys[j].curVars[m];}c++;}}curC++;}// 局部领导者学习阶段(如果局部领导者有更新,则localLimitCount=0,否则localLimitCount++)private void LLLP() {for (int i = 0; i < spiderMonkeyList.size(); i++) {boolean isUpdate = false;for (SpiderMonkey spiderMonkey : spiderMonkeyList.get(i)) {if (localLeaderList.get(i).fit < spiderMonkey.fit) {localLeaderList.set(i, copySpiderMonkey(spiderMonkey));isUpdate = true;}}if (isUpdate) {localLimitCount[i] = 0;} else {localLimitCount[i]++;}}}// 全局领导者学习阶段(如果全局领导者有更新,则globalLimitCount=0,否则globalLimitCount++)private void GLLP() {boolean isUpdate = false;for (int i = 0; i < spiderMonkeyList.size(); i++) {for (SpiderMonkey spiderMonkey : spiderMonkeyList.get(i)) {if (spiderMonkey.fit > bestSpiderMonkey.fit) {bestSpiderMonkey = copySpiderMonkey(spiderMonkey);isUpdate = true;}}}if (isUpdate) {globalLimitCount = 0;} else {globalLimitCount++;}}// 全局领导者阶段(GLP:轮盘赌,随机选取,偏向于对fit值大的蜘蛛猴进行更新)private void GLP() {int c = 0;for (int i = 0; i < spiderMonkeyList.size(); i++) {SpiderMonkey[] spiderMonkeys = spiderMonkeyList.get(i);// 计算fit总和double totalFit = 0;for (SpiderMonkey spiderMonkey : spiderMonkeys) {totalFit += spiderMonkey.fit;}// 轮盘赌的累计概率数组double[] p = new double[spiderMonkeys.length];for (int j = 0; j < p.length; j++) {p[j] = (spiderMonkeys[j].fit / totalFit) + (j == 0 ? 0 : p[j - 1]);}// 局部搜索for (int j = 0; j < localSearchCount; j++) {double r = random.nextDouble();for (int k = 0; k < p.length; k++) {if (r <= p[k]) {for (int m = 0; m < varNum; m++) {double moveDist = random.nextDouble() * (bestSpiderMonkey.curVars[m] - spiderMonkeys[k].curVars[m]) + (random.nextDouble() - 0.5) * 2 * (spiderMonkeys[random.nextInt(spiderMonkeys.length)].curVars[m] - spiderMonkeys[k].curVars[m]);moveSpiderMonkey(spiderMonkeys[k], m, moveDist);}spiderMonkeys[k].curObjValue = getObjValue(spiderMonkeys[k].curVars);spiderMonkeys[k].fit = 1 / spiderMonkeys[k].curObjValue;break;}}}for (int j = 0; j < spiderMonkeys.length; j++) {for (int m = 0; m < spiderMonkeys[j].curVars.length; m++) {positionArr[curC][c][m] = spiderMonkeys[j].curVars[m];}c++;}spiderMonkeyList.set(i, spiderMonkeys);}curC++;}// 局部领导者阶段(LLP:所有的蜘蛛猴都有机会更新自己)private void LLP() {int c = 0;for (int i = 0; i < spiderMonkeyList.size(); i++) {SpiderMonkey[] spiderMonkeys = spiderMonkeyList.get(i);SpiderMonkey localLeader = localLeaderList.get(i);for (int j = 0; j < spiderMonkeys.length; j++) {// 以一定几率更新自己if (random.nextDouble() <= LLP_PR) {SpiderMonkey tempSpiderMonkey = copySpiderMonkey(spiderMonkeys[j]);for (int m = 0; m < varNum; m++) {double moveDist = random.nextDouble() * (localLeader.curVars[m] - tempSpiderMonkey.curVars[m]) + (random.nextDouble() - 0.5) * 2 * (spiderMonkeys[random.nextInt(spiderMonkeys.length)].curVars[m] - tempSpiderMonkey.curVars[m]);moveSpiderMonkey(tempSpiderMonkey, m, moveDist);}tempSpiderMonkey.curObjValue = getObjValue(tempSpiderMonkey.curVars);tempSpiderMonkey.fit = 1 / tempSpiderMonkey.curObjValue;if (greedy) {if (tempSpiderMonkey.fit > spiderMonkeys[j].fit) {spiderMonkeys[j] = tempSpiderMonkey;}} else {spiderMonkeys[j] = tempSpiderMonkey;}}for (int m = 0; m < spiderMonkeys[j].curVars.length; m++) {positionArr[curC][c][m] = spiderMonkeys[j].curVars[m];}c++;}spiderMonkeyList.set(i, spiderMonkeys);}curC++;}// 初始化蜘蛛猴种群private void initSpiderMonkeys() {positionArr = new double[3 * maxGen][spiderMonkeyNum][varNum];SpiderMonkey[] spiderMonkeys = new SpiderMonkey[spiderMonkeyNum];SpiderMonkey localLeader = null;for (int i = 0; i < spiderMonkeyNum; i++) {spiderMonkeys[i] = getRandomSpiderMonkey();if (i == 0) {bestSpiderMonkey = copySpiderMonkey(spiderMonkeys[0]);localLeader = copySpiderMonkey(spiderMonkeys[0]);} else {if (bestSpiderMonkey.fit < spiderMonkeys[i].fit) {bestSpiderMonkey = copySpiderMonkey(spiderMonkeys[i]);localLeader = copySpiderMonkey(spiderMonkeys[0]);}}}spiderMonkeyList.add(spiderMonkeys);localLeaderList.add(localLeader);}// 获取一个随机生成的蜘蛛猴SpiderMonkey getRandomSpiderMonkey() {double[] vars = new double[varNum];for (int j = 0; j < vars.length; j++) {vars[j] = lb[j] + random.nextDouble() * (ub[j] - lb[j]);}double objValue = getObjValue(vars);return new SpiderMonkey(vars.clone(), objValue, 1 / objValue);}// 控制spiderMonkey在第m个维度上移动n个距离public void moveSpiderMonkey(SpiderMonkey spiderMonkey, int m, double n) {// 移动spiderMonkey.curVars[m] += n;// 超出定义域的判断if (spiderMonkey.curVars[m] < lb[m]) {spiderMonkey.curVars[m] = lb[m];}if (spiderMonkey.curVars[m] > ub[m]) {spiderMonkey.curVars[m] = ub[m];}}/*** @param vars 自变量数组* @return 返回目标函数值*/IloCplex cplex = new IloCplex();public double getObjValue(double[] vars) {try {// 更新距离for (int i = 0; i < vars.length; i++) {if (i % 2 == 0) {stockyardList.get(i / 2).x = vars[i];} else {stockyardList.get(i / 2).y = vars[i];}}// 计算距离矩阵double[][] distanceMatrix = new double[stockyardList.size()][constructionSiteList.size()];for (int i = 0; i < distanceMatrix.length; i++) {Stockyard stockyard = stockyardList.get(i);for (int j = 0; j < distanceMatrix[i].length; j++) {ConstructionSite constructionSite = constructionSiteList.get(j);distanceMatrix[i][j] = calcDistance(stockyard.x, stockyard.y, constructionSite.x, constructionSite.y);}}// 开始建模
//            cplex = new IloCplex();// 声明变量IloNumVar[][] x = new IloNumVar[stockyardList.size()][constructionSiteList.size()];for (int i = 0; i < x.length; i++) {for (int j = 0; j < x[i].length; j++) {x[i][j] = cplex.numVar(0, Math.min(stockyardList.get(i).c, constructionSiteList.get(j).d));}}// 构造约束1:必须满足每个工地的需求for (int j = 0; j < constructionSiteList.size(); j++) {IloLinearNumExpr expr = cplex.linearNumExpr();for (int i = 0; i < x.length; i++) {expr.addTerm(1, x[i][j]);}cplex.addEq(expr, constructionSiteList.get(j).d);}// 构造约束2:不能超过每个料场的储量for (int i = 0; i < stockyardList.size(); i++) {cplex.addLe(cplex.sum(x[i]), stockyardList.get(i).c);}// 声明目标函数IloLinearNumExpr target = cplex.linearNumExpr();for (int i = 0; i < x.length; i++) {for (int j = 0; j < x[i].length; j++) {target.addTerm(distanceMatrix[i][j], x[i][j]);}}cplex.addMinimize(target);// 配置cplexcplex.setOut(null);cplex.setWarning(null);cplex.setParam(IloCplex.DoubleParam.EpOpt, EPS);// 开始求解double obj;if (cplex.solve()) {obj = cplex.getObjValue();} else {throw new RuntimeException("此题无解");}cplex.clearModel();return obj;} catch (Exception e) {throw new RuntimeException(e);}}// 复制蜘蛛猴SpiderMonkey copySpiderMonkey(SpiderMonkey old) {return new SpiderMonkey(old.curVars.clone(), old.curObjValue, old.fit);}public static void main(String[] args) throws IloException {// 料场列表List<Stockyard> stockyardList = new ArrayList<>();stockyardList.add(new Stockyard(0, 0, 20));stockyardList.add(new Stockyard(0, 0, 20));// 工地列表List<ConstructionSite> constructionSiteList = getInitConstructionSiteList();long s = System.currentTimeMillis();new SMO_Solver(stockyardList, constructionSiteList).solve();System.out.println("总用时: " + (System.currentTimeMillis() - s) / 1000d + " s");}}

输出结果如下:

0 : 122.18394756340149
1 : 115.22137772493119
2 : 107.64015378143884
3 : 91.25562099863063
4 : 87.27034345689911
5 : 86.08239574989028
6 : 85.5990696901402
7 : 85.5675162336327
8 : 85.40967721594052
9 : 85.33079736839548
10 : 85.29533933219953
11 : 85.27770206804239
12 : 85.27194687104382
13 : 85.26919031512125
14 : 85.26862219676372
15 : 85.26750239234426
16 : 85.26663764799034
17 : 85.26636259651076
18 : 85.26628507350429
19 : 85.26618997863784
20 : 85.26605221867857
21 : 85.26605221867857
22 : 85.26604976682619
23 : 85.26604439739287
24 : 85.26604351700756
25 : 85.26604156579967
26 : 85.26604141563301
27 : 85.26604110466047
28 : 85.2660410153342
29 : 85.26604098426941
30 : 85.26604096946092
31 : 85.26604090826108
32 : 85.26604089012692
33 : 85.26604088253666
34 : 85.26604087662045
35 : 85.26604087515656
36 : 85.26604087344376
37 : 85.26604087292048
38 : 85.26604087263298
39 : 85.26604087239937
40 : 85.26604087223953
41 : 85.26604087214378
42 : 85.26604087212847
43 : 85.2660408721172
44 : 85.26604087211567
45 : 85.2660408721116
46 : 85.26604087211126
47 : 85.26604087211126
48 : 85.26604087211103
49 : 85.26604087211096
50 : 85.26604087211076
51 : 85.2660408721107
52 : 85.2660408721107
53 : 85.26604087211066
54 : 85.26604087211066
55 : 85.26604087211066
56 : 85.26604087211064
57 : 85.26604087211064
58 : 85.26604087211064
59 : 85.26604087211064
变量取值为:[7.25, 7.75, 3.2548825928531566, 5.652332445501583]
最优解为:85.26604087211064
总用时: 0.997 s

四、总结

本博客分别介绍了一种贪心启发式算法和一种群体智能算法求解选址问题,结果表明,贪心启发式算法可以在极短的时间内得到较优的解,而蜘蛛猴优化算法则可以在迭代多次后得到更好的解。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/48131.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

spring异步框架使用教程

背景 在需求开发过程中&#xff0c;为了提升效率&#xff0c;很容易就会遇到需要使用多线程的场景。这个时候一般都会选择建一个线程池去专门用来进行某一类动作&#xff0c;这种任务到来的时候往往伴随着大量的线程被创建调用。而还有另外一种场景是整个任务的执行耗时比较长…

系统架构设计师-信息安全技术(2)

目录 一、安全架构概述 1、信息安全所面临的威胁 二、安全模型 1、安全模型的分类 2、BLP模型 3、Biba 模型 4、Chinese Wall模型 三、信息安全整体架构设计 1、WPDRRC模型 2、各模型的安全防范功能 四、网络安全体系架构设计 1、开放系统互联安全体系结构 2、安全服务与安…

万字长文带你快速了解整个Flutter开发流程

文章目录 背景1.简介与优势Flutter是什么&#xff1f;为什么选Flutter&#xff1f; 2.开发环境搭建安装Flutter SDK配置开发环境 3.创建项目项目结构概览&#xff1a; 4.UI 构建与布局什么是Widget&#xff1a;StatelessWidget和StatefulWidget&#xff1a;Widget的组合&#x…

Java开发面试题 | 2023

Java基础 接口和抽象类的区别&#xff1f;Java动态代理HashMap 底层实现及put元素的具体过程currenthashmap底层实现原理&#xff1f;map可以放null值吗&#xff0c;currenthashmap为什么不能放null值synchronze和reetrantlock区别&#xff1f;怎样停止一个运行中的线程&#…

机器学习笔记 - 使用 AugMix 增强图像分类模型的鲁棒性

一、简述 图像分类模型能够预测与训练数据具有相同分布的数据。然而,在现实场景中,输入数据可能会发生变化。例如,当使用不同的相机进行推理时,照明条件、对比度、颜色失真等可能与训练集不同,并显着影响模型的性能。为了应对这一挑战,Hendrycks 等人提出了 AugMix 算法。…

IP地址SSL证书

在许多企业用例中&#xff0c;公司需要SSL证书作为IP地址。公司使用IP地址通过Internet或Intranet访问各种类型的应用程序。根据组织策略&#xff0c;您希望使用SSL证书保护IP地址。 在本文中&#xff0c;我将向您解释获取IP地址SSL证书的过程&#xff0c;以及哪种类型的SSL证…

实验二 Hdoop2.7.6+JDK1.8+SSH的安装部署与基本操作

系列文章目录 提示&#xff1a;这里可以添加系列文章的所有文章的目录&#xff0c;目录需要自己手动添加 例如&#xff1a;第一章 Python 机器学习入门之pandas的使用 提示&#xff1a;写完文章后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目…

Web和云开发,Rust会起飞?

Web和云开发&#xff0c;Rust会起飞&#xff1f; 一、前言 二、大厂偏爱&#xff0c;Rust的未来 三、Rust做Web的雄心 四、有必要换Rust做Web&#xff1f; 1.效率和性能 2.可靠性和可维护性 五、Rust先苦后甜 六、用Rust前的几个问题 七、开发界的强者 一、前言 去年…

什么是Eureka?以及Eureka注册服务的搭建

导包 <?xml version"1.0" encoding"UTF-8"?> <project xmlns"http://maven.apache.org/POM/4.0.0"xmlns:xsi"http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation"http://maven.apache.org/POM/4.0.0 htt…

《Go 语言第一课》课程学习笔记(六)

变量声明&#xff1a;静态语言有别于动态语言的重要特征 变量所绑定的内存区域是要有一个明确的边界的。也就是说&#xff0c;通过这样一个变量&#xff0c;我们究竟可以操作 4 个字节内存还是 8 个字节内存&#xff0c;又或是 256 个字节内存&#xff0c;编程语言的编译器或解…

知虾|Shopee数据分析工具是什么?Shopee虾皮卖家必备工具

知虾|Shopee数据分析工具是什么&#xff1f;Shopee虾皮卖家必备工具 在当今竞争激烈的电商行业&#xff0c;拥有准确的市场洞察和数据驱动的决策是成功的关键。Shopee作为全球领先的电商平台之一&#xff0c;市场也出现很多为商家提供了一系列强大的工具和功能&#xff0c;其中…

计算机网络-物理层(三)编码与调制

计算机网络-物理层&#xff08;三&#xff09;编码与调制 在计算机网络中&#xff0c;计算机需要处理和传输用户的文字、图片、音频和视频&#xff0c;它们可以统称为消息 数据是运输信息的实体&#xff0c;计算机只能处理二进制数据&#xff0c;也就是比特0和比特1。计算机中…

AIR001开箱测试

最近&#xff0c;合宙的动作还是挺大的&#xff0c;又出了两款AIR001和RP2040&#xff0c;而且前段时间还出了AIR32F103系列&#xff0c;记的21年要采购STM32F1103的时候&#xff0c;1片的价格从开发时的5块涨到了生产阶段的100多&#xff0c;即使最后无奈采用了别的芯片&#…

融云深度参与「新加坡 GTLC 大会」,连接亚太机遇、开拓国际市场

8 月 18 日&#xff0c;由 TGO 鲲鹏会主办的新加坡 GTLC&#xff08;Global Tech Leadership Conference&#xff0c;全球技术领导力大会&#xff09;圆满收官&#xff0c;融云作为共创伙伴深度参与了大会。关注【融云全球互联网通信云】了解更多 本次大会以“Connecting Asia…

Python批量爬虫下载文件——把Excel中的超链接快速变成网址

本文的背景是&#xff1a;大学关系很好的老师问我能不能把Excel中1000个超链接网址对应的pdf文档下载下来。虽然可以手动一个一个点击下载&#xff0c;但是这样太费人力和时间了。我想起了之前的爬虫经验&#xff0c;给老师分析了一下可行性&#xff0c;就动手实践了。    没…

数学建模及数据分析 || 4. 深度学习应用案例分享

PyTorch 深度学习全连接网络分类 文章目录 PyTorch 深度学习全连接网络分类1. 非线性二分类2. 泰坦尼克号数据分类2.1 数据的准备工作2.2 全连接网络的搭建2.3 结果的可视化 1. 非线性二分类 import sklearn.datasets #数据集 import numpy as np import matplotlib.pyplot as…

Web 3.0 安全风险,您需要了解这些内容

随着技术的不断发展&#xff0c;Web 3.0 正在逐渐成为现实&#xff0c;为我们带来了许多新的机遇和挑战。然而&#xff0c;与任何新技术一样&#xff0c;Web 3.0 也伴随着一系列安全风险&#xff0c;这些风险需要被认真对待。在这篇文章中&#xff0c;我们将探讨一些与Web 3.0 …

Excel/PowerPoint柱状图条形图负值设置补色

原始数据&#xff1a; 列1系列 1类别 14.3类别 2-2.5类别 33.5类别 44.5 默认作图 解决方案 1、选中柱子&#xff0c;双击&#xff0c;按如下顺序操作 2、这时候颜色会由一个变成两个 3、对第二个颜色进行设置&#xff0c;即为负值的颜色 条形图的设置方法相同

【STM32】FreeRTOS软件定时器学习

软件定时器 FreeRTOS提供了现成的软件定时器功能&#xff0c;可以一定程度上替代硬件定时器&#xff0c;但精度不高。 实验&#xff1a;创建一个任务&#xff0c;两个定时器&#xff0c;按键开启定时器&#xff0c;一个500ms打印一次&#xff0c;一个1000ms打印一次。 实现&…

023:vue中解决el-date-picker更改样式不生效问题

第023个 查看专栏目录: VUE ------ element UI 本文章目录 修改后的效果示例源代码&#xff08;共52行&#xff09;核心内容步骤&#xff1a;&#xff08;1&#xff09;更改样式&#xff08;2&#xff09;添加参数 专栏目标 在vue项目开发中&#xff0c;我们打算保持颜色的一致…