<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          車輛路徑優(yōu)化問題求解工具Jsprit的簡(jiǎn)單介紹與入門

          共 5292字,需瀏覽 11分鐘

           ·

          2019-09-16 23:20


          今天小編要為大家介紹一款用于求解車輛路徑優(yōu)化問題(VRP)的工具箱---jsprit。大家可能沒聽過這個(gè)求解工具小編也是經(jīng)老師介紹才知道的。這里可以偷偷的告訴大家老師的團(tuán)隊(duì)正在開發(fā)一款更厲害的車輛路徑優(yōu)化問題的求解器將來會(huì)與Jsprit做性能比較。大家可以期待一下我們自己的車輛路徑優(yōu)化問題的求解器哦!

          52dd6e75c413234b96a25ec61de6247a.webp

          jsprit是Github上的一個(gè)開源項(xiàng)目由Stefan Schr?der所創(chuàng)建并由GraphHopper主持。這兩位發(fā)現(xiàn)在車輛路徑規(guī)劃問題應(yīng)用如此廣泛的情況下極少有開源的工具能夠幫助解決帶有不同約束的車輛路徑規(guī)劃問題于是他們就創(chuàng)建并完成了這個(gè)項(xiàng)目。

          1fceb329c0bd1d4a5ff892e37782fa71.webp Jsprit是一個(gè)開源的工具箱,提供用于求解VRP的工具,基于元啟發(fā)式算法(meta-heuristics)。

          2a404f7ecb8137bf4bae04f780b8a4d0.webp什么是元啟發(fā)式算法呢?元啟發(fā)式算法是指一類基于直觀或者經(jīng)驗(yàn)構(gòu)造的算法,它可以在可接受的花費(fèi)(指時(shí)間或空間)下給出問題一個(gè)可行解。許多啟發(fā)式算法是針對(duì)或者是依賴于某一個(gè)特定問題的,而元啟發(fā)式算法則是一些比較通用的啟發(fā)式策略,通常不借助于某個(gè)問題特有的條件,將局部搜索和隨機(jī)相結(jié)合。我們介紹過的蟻群算法、模擬退火算法、遺傳算法等都屬于元啟發(fā)式算法。之所以要做這個(gè)背景介紹就是為了告訴大家jsprit不保證能得到最優(yōu)解。接下來小編將從功能、安裝使用、求解性能和質(zhì)量幾個(gè)方面為大家簡(jiǎn)單地介紹這款工具箱。Jsprit官網(wǎng)
          http://jsprit.github.io/
          https://github.com/graphhopper/jsprit


          01


          Jsprit能干什么



          ??據(jù)官網(wǎng)介紹,jsprit能夠解決下列問題:

          1. 帶容量限制的VRP(Capacitated VRP)

          2. 多場(chǎng)站VRP(VRP with Multiple Depots)

          3. 帶時(shí)間窗的VRP(VRP with Time Windows)

          4. 帶回程的VRP(VRP with Backhauls)

          5. 多車型VRP(VRP with Heterogeneous Fleet)

          6. 取送貨VRP(VRP with Pickups and Deliveries)?

          7. 時(shí)間依賴型VRP(Time-dependent VRP)

          8. 旅行商問題(Traveling Salesman Problem)

          9. Dial-a-Ride問題(Dial-a-Ride Problem)

          除了以上問題外,jsprit還支持以上問題的混合。jsprit作為一個(gè)模塊化的工具箱,方便之處在于,這個(gè)工具箱求解是通過core模塊里的一些組件來構(gòu)建整個(gè)VRP以及構(gòu)建問題的組成元素,例如一個(gè)基本的車輛路徑規(guī)劃問題的代碼里有倉庫、車輛、客戶點(diǎn)這幾個(gè)元素,那么構(gòu)造器會(huì)把這些元素一個(gè)一個(gè)構(gòu)造出來,通過問題的構(gòu)造器把這些元素加入到這個(gè)問題里面,并且告知構(gòu)造器用這些元素構(gòu)造一個(gè)車輛路徑規(guī)劃問題的代碼。


          為什么說這樣方便使用呢?


          一個(gè)基本的車輛路徑規(guī)劃問題的代碼里面,客戶點(diǎn)的屬性可能只有坐標(biāo)和需求量。換句話說,構(gòu)造器在構(gòu)造這個(gè)客戶點(diǎn)的時(shí)候,僅僅設(shè)置了這個(gè)客戶點(diǎn)的坐標(biāo)和需求量,但是除此之外,我們還可以為這個(gè)客戶點(diǎn)設(shè)置一個(gè)時(shí)間窗,設(shè)置服務(wù)時(shí)間以及設(shè)置客戶點(diǎn)的服務(wù)優(yōu)先級(jí)等等,通過這樣對(duì)客戶點(diǎn)的設(shè)置就能夠滿足不同的問題的需求。同理,對(duì)于車輛而言,我們可以用循環(huán)語句構(gòu)建一百個(gè)車輛實(shí)例存到數(shù)組里面。如果要求解一個(gè)多車型問題,我們?cè)跇?gòu)造這些車輛的時(shí)候設(shè)置好不同車型的參數(shù)就可以了。

          b6eb3cd2d1820f437490d4c3be7ca6a3.webp

          而對(duì)于整個(gè)問題的約束條件,在問題的構(gòu)造器里面也可以設(shè)置,例如設(shè)置總的服務(wù)時(shí)間,設(shè)置是否帶有回程等等。

          簡(jiǎn)單地說就是構(gòu)造器既能夠?qū)嵗粋€(gè)個(gè)元素,也能設(shè)置和修改這些元素的屬性從而能夠滿足不同問題的約束條件,這也就是為什么它能夠支持以上問題的混合。

          小編實(shí)踐后發(fā)現(xiàn),這個(gè)工具箱除了上手快,使用方便以外,對(duì)于解的可視化也做得很好,能夠非常詳細(xì)和直觀地表達(dá)解的情況和結(jié)果。


          02如何使用Jsprit


          Jsprit有三個(gè)比較核心的部件,分別是jsprit-core、jsprit-analysis、jsprit-io


          jsprit-core從名字上我們就可以知道這個(gè)絕對(duì)是核心中的核心,里面包含了一些構(gòu)造器。


          jsprit-analysis提供了將求解的結(jié)果進(jìn)行可視化的工具箱,主要依賴于jfree繪圖并通過graphstream進(jìn)行圖形流的處理和展示。這兩個(gè)都是免費(fèi)的工具,需要到網(wǎng)上下載響應(yīng)版本的jar包并在項(xiàng)目里加載,后續(xù)會(huì)給大家介紹。


          jsprit-io則是對(duì)求解的過程等進(jìn)行記錄和輸出。


          此外還有jsprit-instances和jsprit-examples,這兩部分我們?cè)谧约呵蠼鈫栴}的時(shí)候并不需要用到,但是在學(xué)習(xí)的時(shí)候能夠給我們一些幫助。

          jsprit-instances里面有兩個(gè)部分,一個(gè)是instance,另一個(gè)則是讀取算例的代碼,存放在一個(gè)src文件夾中。instance里面有不同約束的VRP的一些經(jīng)典算例,基本都是txt格式的文件,而src文件夾里面則是一些代碼,這些代碼的作用是創(chuàng)建一個(gè)構(gòu)造器然后讀入instance里面的算例,構(gòu)造算例里面的元素。大家可以利用這些代碼來讀入這些算例或者是與這些算例的格式相同的算例,這樣就不用自己寫讀入文件的代碼了。


          jsprit-examples正如它的名字一樣,里面都是一些簡(jiǎn)單的運(yùn)用這個(gè)工具箱的例子,如果大家環(huán)境搭好了而且配置正確的話,examples里面的代碼是可以直接跑的,這一部分的作用就是用簡(jiǎn)單的例子向大家展示這個(gè)工具箱是怎么工作的。


          好了,啰嗦了這么多,我們來動(dòng)手試試吧。

          38597284aa558317d319c84484566553.webp


          Step1

          下載并解壓項(xiàng)目代碼

          jsprit是用JAVA語言寫的,小編推薦用eclipse平臺(tái)來跑JAVA代碼嗷,大家可以直接到官網(wǎng)下載(for free),然后到項(xiàng)目地址

          https://github.com/graphhopper/jsprit下載,這里可以下載zip再進(jìn)行解壓。


          Step2

          下載并解壓外部依賴包

          這一步我們需要下載一些jsprit依賴的外部包,需要的依賴包以及包的版本可以從項(xiàng)目的介紹里看的到,大家只需要到網(wǎng)上搜索下載下來然后解壓就好了,小編建議大家把這些包和上面下載解壓的文件放在一個(gè)目錄里以便于管理,為了方便大家操作,小編已經(jīng)替大家收集好了這些包,跟源代碼打包到一起了,大家直接下載使用就可以了。

          f4dc34946b71dd784d552596ad2b03ad.webp



          Step3

          在Eclipse里面創(chuàng)建一個(gè)項(xiàng)目并導(dǎo)入上述步驟中下載的包


          然后就在eclipse里面新建一個(gè)項(xiàng)目。

          995c83c74e1725c3c99036eb74184ab9.webp

          在新建的項(xiàng)目代碼文件夾里加載jsprit的工具包。在src文件夾右鍵->import->General->File System->Browse

          b0c8f0db160f1b2d44f4dc55dab219a4.webp

          然后找到剛才的解壓包解壓的位置,找到j(luò)sprit-core等包,一直點(diǎn)進(jìn)去jsprit-core\src\main\java,然后選中左側(cè)的java文件夾,再點(diǎn)擊finish就可以了。

          13554bb8f4184fc7fa6cbb318a6f36b8.webp

          下一步就是外部依賴包的引入了,這里我們以slf4j這個(gè)包為例子,這里假設(shè)大家都已經(jīng)下載并解壓了slf4j這個(gè)包,然后在我們新建的java項(xiàng)目上右鍵->Build Path->Add External Archives,接下來會(huì)跳出來一個(gè)選擇框,找到解壓的位置,一直點(diǎn)進(jìn)去直到看到有這些jar包,導(dǎo)入slf4j-api-1.7.25.jar和slf4j-jdk14-1.7.25.jar兩個(gè)包。其它的包依次導(dǎo)入就可以了。

          51a20246d8667e503ec1391c260ba6ed.webp


          Step4

          寫代碼

          在準(zhǔn)備好上面這些東西之后,我們就可以開始愉快地寫代碼了。

          上述提到有幾個(gè)核心的組件,這里我們以解某個(gè)VRP為例,看看如何使用這些組件,為了方便大家理解,我們先用圖大概地給大家介紹一下這幾個(gè)組件是怎么合作的。


          a7db6d40c4a919d6183de79255824d98.webp


          864c96346b4500da0ef27f5634df3ecd.webp


          可能大家還是有點(diǎn)懵,下面我們把代碼放上來,結(jié)合代碼大家體會(huì)一下)

          package?maintest;
          import?com.graphhopper.jsprit.analysis.toolbox.GraphStreamViewer;
          import?com.graphhopper.jsprit.analysis.toolbox.GraphStreamViewer.Label;
          import?com.graphhopper.jsprit.analysis.toolbox.Plotter;
          import?com.graphhopper.jsprit.core.algorithm.VehicleRoutingAlgorithm;
          import?com.graphhopper.jsprit.core.algorithm.box.Jsprit;
          import?com.graphhopper.jsprit.core.problem.Location;
          import?com.graphhopper.jsprit.core.problem.VehicleRoutingProblem;
          import?com.graphhopper.jsprit.core.problem.job.Service;
          import?com.graphhopper.jsprit.core.problem.solution.VehicleRoutingProblemSolution;
          import?com.graphhopper.jsprit.core.problem.vehicle.VehicleImpl;
          import?com.graphhopper.jsprit.core.problem.vehicle.VehicleImpl.Builder;
          import?com.graphhopper.jsprit.core.problem.vehicle.VehicleType;
          import?com.graphhopper.jsprit.core.problem.vehicle.VehicleTypeImpl;
          import?com.graphhopper.jsprit.core.reporting.SolutionPrinter;
          import?com.graphhopper.jsprit.core.util.Solutions;


          import?java.io.BufferedReader;
          import?java.io.File;
          import?java.io.FileNotFoundException;
          import?java.io.FileReader;
          import?java.util.ArrayList;
          import?java.util.Collection;
          import?java.util.Scanner;
          public?class?thetest?{
          /**
          ?*?@param?args
          ?*/

          ????static?int[][]?customerNode?;//記錄客戶點(diǎn)信息
          ????static?int?capacity?=?0;//車輛容量
          ????static?int?xdepot?=?0;//倉庫橫坐標(biāo)
          ????static?int?ydepot?=?0;//倉庫縱坐標(biāo)
          ????static?int?numberOfCustomer?=?0;
          ????final?static?int?WEIGHT_INDEX?=?0;
          public?static?void?main(String[]?args)?{
          ????//創(chuàng)建輸出文件
          ????File?dir?=?new?File("output");
          ????if?(!dir.exists())?{
          ????????System.out.println("creating?directory?./output");
          ????????boolean?result?=?dir.mkdir();
          ????????if?(result)?System.out.println("./output?created");
          ????}
          ????String?path?=?"data/examples.txt";
          ????readData(path);
          ????buildProblem();
          }
          public?static?void?readData(String?path)?{
          ????//讀入數(shù)據(jù)
          ????try?{
          ????????Scanner?cin?=?new?Scanner(new?BufferedReader(new?FileReader(path)));
          ????????numberOfCustomer?=?cin.nextInt();
          ????????cin.next();
          ????????capacity?=?cin.nextInt();
          ????????xdepot?=?cin.nextInt();
          ????????ydepot?=?cin.nextInt();
          ????????customerNode?=?new?int[numberOfCustomer][3];
          ????????for(int?i?=?0;i????????????cin.nextInt();
          ????????????for(int?j?=?0;j<3;j++)?{
          ????????????????customerNode[i][j]?=?cin.nextInt();
          ????????????}
          ????????}
          ????????cin.close();
          ????}?catch?(FileNotFoundException?e)?{
          ????????e.printStackTrace();
          ????}
          }
          public?static?void?buildProblem()?{
          ????//建立一個(gè)求解器類型實(shí)例,為vehicleType
          ????VehicleTypeImpl.Builder?vehicleTypeBuilder?=?VehicleTypeImpl.Builder.newInstance("vehicleType").addCapacityDimension(WEIGHT_INDEX,?capacity);
          ????VehicleType?vehicleType?=?vehicleTypeBuilder.build();
          ????//建立一個(gè)求解器實(shí)例,名稱為vechicle,坐標(biāo)為讀入的坐標(biāo),設(shè)定求解器的類型
          ????Builder?vehicleBuilder?=?VehicleImpl.Builder.newInstance("vehicle");
          ????vehicleBuilder.setStartLocation(Location.newInstance(xdepot,?ydepot));
          ????vehicleBuilder.setType(vehicleType);
          ????VehicleImpl?vehicle?=?vehicleBuilder.build();
          ????//聲明服務(wù)點(diǎn)的集合
          ????Collection?serviceNode?=?new?ArrayList();
          ????//讀入各服務(wù)點(diǎn)的數(shù)據(jù)
          ????for(int?i?=?0;?i?????????Service?serviceNodeTemp?=?Service.Builder.newInstance(""+i).addSizeDimension(WEIGHT_INDEX,?customerNode[i][2]).setLocation(Location.newInstance(customerNode[i][0],?customerNode[i][1])).build();
          ????????serviceNode.add(serviceNodeTemp);
          ????}
          ????//實(shí)例化一個(gè)VRP的builder,并將中心點(diǎn)和服務(wù)點(diǎn)加入后實(shí)例化。
          ????VehicleRoutingProblem.Builder?vrpBuilder?=?VehicleRoutingProblem.Builder.newInstance();
          ????vrpBuilder.addVehicle(vehicle);
          ????vrpBuilder.addAllJobs(serviceNode);
          ????VehicleRoutingProblem?problem?=?vrpBuilder.build();
          ????//為問題獲取算法
          ????VehicleRoutingAlgorithm?algorithm?=?Jsprit.createAlgorithm(problem);
          ????//記錄解的集合記錄,并尋找最優(yōu)解
          ????Collection?solutions?=?algorithm.searchSolutions();
          ????VehicleRoutingProblemSolution?bestSolution?=?Solutions.bestOf(solutions);
          ????//現(xiàn)實(shí)求解的結(jié)果詳情
          ????SolutionPrinter.print(problem,?bestSolution,?SolutionPrinter.Print.VERBOSE);
          ????//將求解的結(jié)果進(jìn)行可視化
          ????new?Plotter(problem,bestSolution).plot("output/plot.png","simple?example");
          ????new?GraphStreamViewer(problem,?bestSolution).labelWith(Label.ID).setRenderDelay(200).display();
          }
          }


          經(jīng)過以上四個(gè)Step,我們就能使用這個(gè)工具箱來求解一個(gè)帶容量約束的車輛路徑規(guī)劃問題了。接下來,我們來看看運(yùn)行的結(jié)果是怎么樣的,首先我們來看看core.reporting這個(gè)組件給出的求解信息


          5cb533e14048374d347bf1d45053a0b2.webp

          08719c1e57d8ef0def3215a7e1f31147.webp

          0873e72546ebf3fe1b063f010397eb21.webp

          b8046dfb1dda4f884f0f2fbc6e3e07a0.webp

          c4f0e4365dc2fb40e3e18732e05f4ffc.webp

          b900f0bcae9a253e15c20d00e3b7cd33.webp


          • 通過以上內(nèi)容大家可以看到給出的求解信息還是非常的詳細(xì)的。

          • 解的詳細(xì)結(jié)果打印的格式是統(tǒng)一的,但是這個(gè)VRP的代碼里面并不涉及顧客服務(wù)時(shí)間窗。

          • 大家可以看到求解的迭代次數(shù),求解時(shí)間為7.68秒,總路程為524.6111466425074,注意這里用的是歐氏距離,在構(gòu)建問題的時(shí)候可以將cost設(shè)為曼哈頓距離。

          • 共使用了五輛車輛,并在detail中給出了每個(gè)車輛的路徑,這個(gè)結(jié)果可以用jsprit-io組件寫出為xml文件,但是這個(gè)工具箱更秀的是它能直接將上述路線直接生成路線圖并輸出,請(qǐng)看:


          c7645995286ef6ff50d3c60c8b623a46.webp


          是不是很省事?圖畫出來也還不錯(cuò),你以為這就完了?還記得上文導(dǎo)入的外部包里有一個(gè)graphstream嗎,這個(gè)東西可以動(dòng)態(tài)地呈現(xiàn)整個(gè)運(yùn)輸過程,來看看效果圖吧


          30ec6b3ab4bcf077e5488e60a07e0a3d.webp


          怎么樣,是不是很酷炫?而且上述可視化只需要兩行代碼,就能還你一幅酷炫的路線圖。

          cbf3b4225df5f3212f483addc142f24d.webp

          02與Cplex求解對(duì)比


          上述是一個(gè)簡(jiǎn)單的入門的例子,前文提到這個(gè)工具箱是基于元啟發(fā)式算法的,在上述算例中,得到的解是算例的最優(yōu)解,那它跟例如Cplex這樣的求解器在求解性能上會(huì)差多少呢,這里我們以一個(gè)帶時(shí)間窗的車輛路徑規(guī)劃問題的代碼為例來比較一下兩者的求解結(jié)果。由于篇幅關(guān)系,這里就只放用該求解器求解帶時(shí)間窗的車輛路徑規(guī)劃問題的代碼,用Cplex求解的代碼以及用到的算例和外部依賴包等等都會(huì)給大家。


          代碼如下:

          import?com.graphhopper.jsprit.analysis.toolbox.GraphStreamViewer;
          import?com.graphhopper.jsprit.analysis.toolbox.Plotter;
          import?com.graphhopper.jsprit.analysis.toolbox.GraphStreamViewer.Label;
          import?com.graphhopper.jsprit.core.algorithm.VehicleRoutingAlgorithm;
          import?com.graphhopper.jsprit.core.algorithm.box.Jsprit;
          import?com.graphhopper.jsprit.core.problem.Location;
          import?com.graphhopper.jsprit.core.problem.VehicleRoutingProblem;
          import?com.graphhopper.jsprit.core.problem.job.Service;
          import?com.graphhopper.jsprit.core.problem.solution.VehicleRoutingProblemSolution;
          import?com.graphhopper.jsprit.core.problem.vehicle.VehicleImpl;
          import?com.graphhopper.jsprit.core.problem.vehicle.VehicleImpl.Builder;
          import?com.graphhopper.jsprit.core.problem.vehicle.VehicleType;
          import?com.graphhopper.jsprit.core.problem.vehicle.VehicleTypeImpl;
          import?com.graphhopper.jsprit.core.reporting.SolutionPrinter;
          import?com.graphhopper.jsprit.core.util.ManhattanCosts;
          import?com.graphhopper.jsprit.core.util.Solutions;
          import?java.io.BufferedReader;
          import?java.io.FileNotFoundException;
          import?java.io.FileReader;
          import?java.util.ArrayList;
          import?java.util.Collection;
          import?java.util.Scanner;
          public?class?Vrptw_test?{
          ????static?int?capacity;
          ????static?int?xdepot;
          ????static?int?ydepot;
          ????static?int?numberOfCustomer?=?30;//這里選取30個(gè)客戶點(diǎn)
          ????final?static?int?WEIGHT_INDEX?=?0;
          ????static?int[][]?customerNode;//用戶點(diǎn)數(shù)據(jù)
          ????public?static?void?main(String[]?args)?{
          ????????String?path?=?"data/c104.txt";
          ????????readData(path);
          ????????buildProblem();
          ????}
          ????public?static?void?readData(String?path)?{
          ????????//讀入數(shù)據(jù)
          ????????try?{
          ????????????Scanner?cin?=?new?Scanner(new?BufferedReader(new?FileReader(path)));
          ????????????xdepot?=?cin.nextInt();
          ????????????ydepot?=?cin.nextInt();
          ????????????capacity?=?cin.nextInt();
          ????????????customerNode?=?new?int[numberOfCustomer][6];
          ????????????for(int?i?=?0;i????????????????cin.nextInt();
          ????????????????for?(int?j?=?0;j<6;j++)?{
          ????????????????????customerNode[i][j]?=?cin.nextInt();
          ????????????????}
          ????????????}
          ????????????cin.close();
          ????????}?catch?(FileNotFoundException?e)?{
          ????????????e.printStackTrace();
          ????????}
          ????}
          ????public?static?void?buildProblem()?{
          ????????//實(shí)例化問題的類型
          ????????VehicleTypeImpl.Builder?vehicleTypeBuilder?=?VehicleTypeImpl.Builder.newInstance("vehic
          leType"
          )
          ????????????.addCapacityDimension(WEIGHT_INDEX,?capacity).setCostPerWaitingTime(1.);
          ????????VehicleType?vehicleType?=?vehicleTypeBuilder.build();
          ????????Builder?vehicleBuilder?=?Builder.newInstance("vehicle");
          ????????//設(shè)置中心的坐標(biāo)
          ????????vehicleBuilder.setStartLocation(Location.newInstance(xdepot,?ydepot));
          ????????//最長(zhǎng)時(shí)間
          ????????vehicleBuilder.setLatestArrival(1351);
          ????????vehicleBuilder.setType(vehicleType);
          ????????//實(shí)例化構(gòu)造器
          ????????VehicleImpl?vehicle?=?vehicleBuilder.build();
          ????????//構(gòu)建并實(shí)例化所有的客戶點(diǎn)
          ????????Collection?serviceNode?=?new?ArrayList();
          ????????for(int?i?=?0;i????????????Service?temp?=?Service.Builder.newInstance(""+i)
          ????????????????????.addTimeWindow(customerNode[i][3],customerNode[i][4])
          ????????????????????.addSizeDimension(WEIGHT_INDEX,?customerNode[i][2])
          ????????????????????.setServiceTime(customerNode[i][5])
          ????????????????????.setLocation(Location.newInstance(customerNode[i][0],?customerNode[i][1]))
          ????????????????????.build();
          ????????????serviceNode.add(temp);
          ????????}
          ????????//構(gòu)造問題
          ????????VehicleRoutingProblem.Builder?vrpBuilder?=?VehicleRoutingProblem.Builder.newInstance();
          ????????vrpBuilder.addVehicle(vehicle);
          ????????vrpBuilder.addAllJobs(serviceNode);
          ????????vrpBuilder.setFleetSize(VehicleRoutingProblem.FleetSize.INFINITE);
          ????????//vrpBuilder.setRoutingCost(new?ManhattanCosts());//這一行是設(shè)置花費(fèi)為曼哈頓距離
          ????????VehicleRoutingProblem?problem?=?vrpBuilder.build();
          ????????//根據(jù)問題尋找算法和solution
          ????????VehicleRoutingAlgorithm?algorithm?=?Jsprit.createAlgorithm(problem);
          ????????Collection?solutions?=?algorithm.searchSolutions();
          ????????//尋找BestSolution
          ????????VehicleRoutingProblemSolution?bestSolution?=?Solutions.bestOf(solutions);
          ????????//打印求解過程和結(jié)果
          ????????SolutionPrinter.print(problem,?bestSolution,?SolutionPrinter.Print.VERBOSE);
          ????????//繪圖
          ????????new?Plotter(problem,bestSolution).setLabel(Plotter.Label.ID).plot("output/plot2.png","mtw");
          ????????new?GraphStreamViewer(problem,?bestSolution).labelWith(Label.ID).setRenderDelay(300).display();
          ????}
          }


          然后我們先來看一下調(diào)用Cplex給出的求解結(jié)果

          c88c29539cbfc04b19b56a39e5504aa6.webp

          再來看看這個(gè)工具箱給出的求解結(jié)果,為了減少篇幅,這里貼部分結(jié)果

          d8682c4c07fb1273c59e141c73650730.webp

          0847202a49ada21a51db7ea48b95fe2b.webp很遺憾,雖然這個(gè)工具箱的速度比Cplex要快得多,但是精確度上還是差得還是有點(diǎn)遠(yuǎn)的。當(dāng)然我們可以修改工具箱源代碼里面的迭代次數(shù),這樣有可能會(huì)達(dá)到一個(gè)更優(yōu)的解,但是這樣做也會(huì)增加求解的時(shí)間,這個(gè)取舍就取決于使用者了,由于篇幅和時(shí)間的原因,這里不可能作大量的測(cè)試。cf2ebb29e5d7f317a7a964d5eb876d4d.webp

          1ae7ad2626c71fd6da315d1d176c3794.webp



          小結(jié)


          雖然這個(gè)工具箱不一定能找到最優(yōu)解,而且使用前需要導(dǎo)入許多外部依賴包,也要求使用者要有一點(diǎn)JAVA編程的基礎(chǔ),但是這個(gè)工具箱的一大優(yōu)點(diǎn)是它的可視化做的很好,解的詳細(xì)信息也可以很直觀地表示出來,各個(gè)組件是模塊化的,掌握和理解起來不會(huì)太難。小編覺得最好的理解和學(xué)習(xí)方式是讀代碼,作者在Github上面也給出了很多代碼實(shí)例供大家學(xué)習(xí)。總的來說小編還是覺得這個(gè)東西不錯(cuò)的,起碼在使用上還是比Cplex方便一些的,正所謂技多不壓身,各位可以學(xué)一學(xué),看一看啦。

          bc068e17672c4af31f876a4ced0f236a.webpENDbc068e17672c4af31f876a4ced0f236a.webp


          欲下載所用源代碼和外部依賴包,請(qǐng)移步留言區(qū)。

          6b2591904e1271056a1206452b65ca72.webp

          -The End-

          文案 / 排版 / 代碼 莊浩城

          指導(dǎo)老師 / 秦虎 華中科技大學(xué)管理學(xué)院 [email protected]



          瀏覽 151
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          評(píng)論
          圖片
          表情
          推薦
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  日韩每日更新 | 欧美成手机在线 | 亚洲狼人综合 | 国产高清无码一级片 | www.91一区二区 |