基於迪克斯特拉(Dijkstra)演算法的物流最佳化系統(Java語言)
作者 郭世龍
演算法介紹
Dijkstra演算法是由荷蘭電腦科學家艾茲格·迪克斯特拉發現的。演算法解決的是有向圖中最短路徑問題。舉例來說,如果圖中的頂點表示配送點,而邊上的權重表示各配送點間開車行經的距離。 Dijkstra演算法可以用來找到兩個配送點之間的最短路徑。Dijkstra演算法的輸入包含了一個有權重的有向圖G,以及G中的一個來源頂點S。 我們以V表示G中所有頂點的集合。 每一個圖中的邊,都是兩個頂點所形成的有序元素對。(u,v)表示從頂點u到v有路徑相連。 以E所有邊的集合,而邊的權重則由權重函數w: E → [0, ∞]定義。 因此,w(u,v)就是從頂點u到頂點v的非負花費值(cost)。 邊的花費可以想像成兩個頂點之間的距離。任兩點間路徑的花費值,就是該路徑上所有邊的花費值總和。 已知有V中有頂點s及t,Dijkstra演算法可以找到s到t的最低花費路徑(i.e. 最短路徑)。 這個演算法也可以在一個圖中,找到從一個頂點s到任何其他頂點的最短路徑。
基本思想是:設定一個頂點的集合s,並不斷地擴充這個集合,一個頂點屬於集合s若且唯若從源點到該點的路徑已求出。開始時s中僅有源點,並且調整非s中點的最短路徑長度,找當前最短路徑點,將其加入到集合s,直到終點在s中。具體的演算法過程可以參考圖論的書籍。
系統介紹 系統以武漢市為例,自訂了一些配點作為定點,提取了可行道路作為邊,並且自訂了邊之間的權重,權重這裡代表行駛時間。1,圖2。系統實現了求任意兩點之間的最短路徑3。作為附加功能,實現了螢幕截取最佳化圖以及列印最佳化圖的功能。 圖1 武漢市地圖圖2 抽象出來的點和邊
圖3 最優路徑圖
程式解析 在系統實現的程式中共聲明了六個類:主架構類Logistics,該類繼承了JFrame類,用作繪圖面板、文字框、菜單的容器及事件響應;繪圖面板類computermap,該類繼承了JPanel類,用作座標系的繪製、圖的繪製;列印類printer,該類實現了Printable介面,用來實現地圖的列印功能;Dijkstra類和MinShortPath類 用來實現迪克斯特拉演算法;Side類用來實現對邊的操作。 繪圖功能是通過computermap類來現。該類繼承於JPanel類,JPanel用作繪圖面板。JPanel類中的PaintCompenent()函數用來負責繪製組件,該函數在必要的時候會自動調用,比如第一次啟動程式、面板大小或位置被調整、有新組件加入面板等。程式不能直接調用PaintCompenent()函數,否則會引起噴繪系統的混亂,但是可調用repaint()函數來實現組件的重繪,repaint()函數將在恰當的時候調用PaintCompenet()函數。 程式中最可能覆蓋的方法是PaintCompenent(),它是組件重繪自身的三個方法中的一個。這三個方法以下面的順序發生: paintComponent——繪製的主要方法。預設情況下,它首先繪製背景,然後繪製程式定製的圖形。 paintBorder——繪製組件的邊框。不能直接調用或覆蓋該方法。 paintChildren—— 通知群組件重繪自身來重繪子組件。不能直接調用或覆蓋該方法。 程式通過覆蓋paintComponent()方法來實現繪圖功能。首先在paintComponent()調用超類的paintComponent()函數實現超類中超類函數的功能,然後定製將要繪製的圖形。 代碼:public void paintComponent(Graphics ge)
{
Graphics2D g=(Graphics2D) ge;
super.paintComponent(g); //顯示白色,如果沒有super則顯示灰色
panelSize = getSize();
RectPoint=this.getLocation();//getLocation()獲得當前組件的螢幕座標
//g.setColor(Color.gray);
g.setColor(Color.green);
//繪製X、Y軸
g.drawLine(10,panelSize.height-10,10,0);
g.drawLine(10,panelSize.height-10,panelSize.width,panelSize.height-10);
g.drawString("0",3,panelSize.height-2);
g.drawString(new Integer((int)(panelSize.height/10)).toString(),20,20);
g.drawString(new Integer((int)(panelSize.width/10)).toString(),panelSize.width-30,panelSize.height-20);
//繪製Y軸箭頭
g.drawLine(panelSize.width,panelSize.height-10,panelSize.width-10,panelSize.height-5);
g.drawLine(panelSize.width,panelSize.height-10,panelSize.width-10,panelSize.height-15);
//繪製X軸箭頭
g.drawLine(10,0,5,5);
g.drawLine(10,0,15,5);
//繪製刻度
//繪製Y軸刻度
int isomerous1 = panelSize.width/10;
for(int j = 0;j<isomerous1 ;j++)
{
g.drawLine(j*10,panelSize.height-10,j*10,panelSize.height-15);
}
//繪製X軸刻度
int isomerous2 =panelSize.height/10;
for(int j = 0;j<isomerous2 ;j++)
{
g.drawLine(10,panelSize.height-j*10,15,panelSize.height-j*10);
}
//to draw Logistics map Sides
for(Side iterator : mapSide)
{
float mapPointX1=30+(ArryListLine.get(iterator.getNode()-1).x )* panelSize.width/12;
float mapPointY1=30+(ArryListLine.get(iterator.getNode()-1).y )* panelSize.height/9;
float mapPointX2=30+(ArryListLine.get(iterator.getPreNode()-1).x )* panelSize.width/12;
float mapPointY2=30+(ArryListLine.get(iterator.getPreNode()-1).y )* panelSize.height/9;
int X1=(int)mapPointX1; int Y1=(int) mapPointY1;
int X2=(int)mapPointX2; int Y2=(int) mapPointY2;
Color colorCurrent=g.getColor();
g.setColor(Color.orange);
g.setStroke(new BasicStroke(2.0f));
g.drawOval(X1-2,Y1-2, 6, 6);
g.drawString(new Integer(mapSide.get(0).getPreNode()).toString(), (int)(0.4*panelSize.width/12+30-5),(int)(1.0*panelSize.height/9+30-5));
g.drawString(new Integer( iterator.getNode()).toString(),X1-5,Y1-5);
g.drawOval(X2-2,Y2-2, 6, 6);
g.setStroke(new BasicStroke());
g.setColor(Color.gray);
g.drawLine(X1,Y1,X2,Y2);
g.setColor(colorCurrent);
//to draw the minishort path ,the elements of ArryListOptLine are added into ArryListOptLine in Dijkatra class.
for(int i=0;i<ArryListOptLine.size()-1;i++)
{
g.setColor(Color.blue);
g.setStroke(new BasicStroke(0.5f));
float PointX1=0+(ArryListLine.get(ArryListOptLine.get(0)-1).x)* panelSize.width/12;
float PointY1=0+(ArryListLine.get(ArryListOptLine.get(0)-1).y)* panelSize.height/9;
float PointX2=60+(ArryListLine.get(ArryListOptLine.get(ArryListOptLine.size()-1)-1).x )* panelSize.width/12;
float PointY2=150+(ArryListLine.get(ArryListOptLine.get(ArryListOptLine.size()-1)-1).y )* panelSize.height/9;
g.drawRect((int)PointX1,(int)PointY1,((int)PointX2-(int)PointX1),((int)PointY2-(int)PointY1) );
float OptmapPointX1=30+(ArryListLine.get(ArryListOptLine.get(i)-1).x)* panelSize.width/12;
float OptmapPointY1=30+(ArryListLine.get(ArryListOptLine.get(i)-1).y)* panelSize.height/9;
float OptmapPointX2=30+(ArryListLine.get(ArryListOptLine.get(i+1)-1).x )* panelSize.width/12;
float OptmapPointY2=30+(ArryListLine.get(ArryListOptLine.get(i+1)-1).y )* panelSize.height/9;
Color colCurrent=g.getColor();
g.setColor(Color.green);
g.setStroke(new BasicStroke(3.0f));
g.drawLine((int)OptmapPointX1,(int)OptmapPointY1,(int)OptmapPointX2,(int)OptmapPointY2);
g.setColor(colCurrent);
g.setStroke(new BasicStroke());
}
}
}
不足之處程式使用的是有向圖的方法,對於起點編號在右而終點編號在左和點之間不能得到最佳化的路徑。需要源碼請留言。
辛苦的工作,快樂的生活