[英]Brute force algorithm for the Traveling Salesman Problem in Java
我正在學校的一個數學課上做項目,我選擇做“旅行推銷員問題”,這是我一直想做的事情。 但是,我的蠻力解決算法遇到了問題。
* 請轉到底部的更新以查看代碼的最新版本
如果您知道旅行商問題是什么,請跳過此段落:總而言之,TSP如下所示:您是一名推銷員,想要訪問區域中的每個城市(一個城市本質上就是地圖上的一個點) 。 在有界的x和y區域中有“ n”座城市,並且每個城市都與每個城市相連(假設是一條直線道路)。 您需要在允許訪問每個城市的城市中找到最短的路線。我想使用的算法之一(並且我將需要測試其他算法)是蠻力法,它會檢查所有可能的路線並返回最短的路線路線。 之所以不總是使用它,是因為它要求我們檢查(n-1)! 可能的路線,並且隨着“ n”的增加,這個數目變得越來越大-實際上,只有50個城市,那就是608281864034267560872252163321295376887552831379210240000000000要檢查的路線。
假設所有示例均假設我們將使用一個具有4個城市的任意區域 (即使該算法可以處理n個城市。我們也不在乎距離-我們希望以粗暴方式擊中每條可能的路線力)。
這是演示我在說什么的簡單圖片(我從4個城市開始,以檢查該過程是否正常運行)
這是蠻力算法(假定所有其他調用的方法都能正常工作,因為它們確實起作用):
(請在下面查看更多說明)
[碼]
public void BruteForceFindBestRoute(Route r) //Must start r having 1 unflagged city to begin with
{
if(!r.allFlagged() && r.route.size() != m.cities.size())
{
/*STEP 1 Begin with last unflagged city*/
City pivot = r.lastCityAdded();
/*STEP 2: Flag city*/
pivot.visited = true;
/*STEP 3: Find cities "NOT IN ROUTE"*/
ArrayList<City> citiesNotInRoute = new ArrayList<City>();
for(int i = 0; i<m.cities.size(); i++)
{
if(!r.isCityInRoute(m.cities.get(i).name))
{
citiesNotInRoute.add(m.cities.get(i));
}
}
/*STEP 4: Recursively call BruteForceFindBestRoute() using these cities added to the end of our original route*/
for(int i = 0; i<citiesNotInRoute.size(); i++)
{
Route newRoute = r;
newRoute.addToRoute(citiesNotInRoute.get(i));
BruteForceFindBestRoute(newRoute);
}
}
/*STEP 5: If the route is full but the last city isn't flagged, then flag it call BruteForceFindBestRoute() again, with the last city flagged*/
else if(!r.allFlagged() && r.route.size() == m.cities.size())
{
if(r.allFlaggedButLast())
{
Route x = r;
x.flagLastCity();
BruteForceFindBestRoute(x);
}
}
/*STEP 6: If all cities are flagged, the route is full. Check to see if it's the best route.*/
else if(r.allFlagged())
{
if(IsBestRoute(r))
bestRoute = r;
}
else
System.err.println("Error: somehow all cities got flagged, but the route isn't full");
}
這是我的邏輯:(注意:城市對象具有一個名為“ visited”的“標志”布爾變量)
(如果未標記所有路線,並且該路線未包含每個可能的城市)
(如果未標記所有路線,但該路線包含每個城市)
(否則...這意味着該路線已標記每個城市並包含每個可能的城市)
此圖像將幫助我解釋問題...因此,程序正確地沿着左側向下移動。 但是,在到達最低點之后,人們會期望遞歸會跳回到步驟4,它確實會這樣做。 但是,R現在沒有標記A城市而B沒有標記城市B,然后遞歸地在包含Aflag和B的“新路線”上調用自己,R現在包括了所有4個城市,並且標記了所有4個城市。 之所以失敗,是因為它再次將城市D添加到“ newRoute”中,然后再次遞歸調用自身,並且在另一種方法中,由於我的區域中沒有5個城市,但錯誤地在r路徑中有5個城市,我們得到了數組錯誤(A,B,C,D,D)。
問題與在循環中調用遞歸有關,或者與在遞歸調用中引用路由“ r”有關。
如果您有任何想法,我將非常感謝您的幫助。
感謝任何會幫助我的人。 我會將整個項目發送給任何願意提供幫助的人。
更新
好吧,所以我試圖簡化和簡化我的原始方法,這就是我所擁有的:
public void BruteForceFindBestRoute(Route r, ArrayList<City> citiesNotInRoute)
{
if(!citiesNotInRoute.isEmpty())
{
for(int i = 0; i<citiesNotInRoute.size(); i++)
{
City justRemoved = (City) citiesNotInRoute.remove(0).clone();
Route newRoute = (Route) r.clone();
newRoute.addToRoute(justRemoved);
BruteForceFindBestRoute(newRoute, citiesNotInRoute);
citiesNotInRoute.add(justRemoved);
}
}
else //if(citiesNotInRoute.isEmpty())
{
if(IsBestRoute(r))
bestRoute = r;
}
}
問題是for循環中的變量i似乎失去了它的含義,即當我們退出遞歸時,循環不會繼續。 有想法嗎?
遞歸調用返回后,您應該從路線中刪除城市。 你做這個:
Route newRoute = r;
newRoute.addToRoute(citiesNotInRoute.get(i));
BruteForceFindBestRoute(newRoute);
但絕不newRoute.removeFromRoute
或類似的東西。
請注意,您正在編寫Java,在Java中,對象的分配是通過reference完成的 。 這意味着r
和newRoute
是同一對象 。 newRoute
不是您可能期望的r
的獨立副本。 因此,對newRoute
任何修改也會更改r
。 您可能要在此處明確復制路線。 Java的術語是clone 。 確保克隆足夠深,即克隆所有相關的數據結構,而不是在原始克隆與其克隆之間共享它們。
注意:在很多地方都可以提高代碼效率,但是由於在任何情況下蠻力都遠不能提高效率,並且您只在談論幾個城市,也許您不必在意。 但是,如果您要研究替代方案,請考慮為所有未訪問的城市維護一個鏈接列表。 每次調用都將遍歷該列表,刪除一個元素,遞歸然后將該元素放回原處。 無需在每次調用時從頭開始構建此列表。 可以將跳舞鏈接的想法巧妙地應用於此任務,以替代預制的鏈接列表實現。
編輯:
您的代碼的以下變體對我有用:
import java.util.*;
class SO11703827 {
private static ArrayList<Integer> bestRoute;
public static void bruteForceFindBestRoute
(ArrayList<Integer> r,
ArrayList<Integer> citiesNotInRoute)
{
if(!citiesNotInRoute.isEmpty())
{
for(int i = 0; i<citiesNotInRoute.size(); i++)
{
Integer justRemoved =
(Integer) citiesNotInRoute.remove(0);
ArrayList<Integer> newRoute =
(ArrayList<Integer>) r.clone();
newRoute.add(justRemoved);
bruteForceFindBestRoute(newRoute, citiesNotInRoute);
citiesNotInRoute.add(justRemoved);
}
}
else //if(citiesNotInRoute.isEmpty())
{
if(isBestRoute(r))
bestRoute = r;
}
}
private static boolean isBestRoute(ArrayList<Integer> r) {
System.out.println(r.toString());
return false;
}
public static void main(String[] args) {
ArrayList<Integer> lst = new ArrayList<Integer>();
for (int i = 0; i < 6; ++i)
lst.add(i);
ArrayList<Integer> route = new ArrayList<Integer>();
bruteForceFindBestRoute(route, lst);
}
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.