Java中旅行商问题的蛮力算法

Java中旅行商问题的蛮力算法,java,algorithm,recursion,traveling-salesman,Java,Algorithm,Recursion,Traveling Salesman,我正在为学校的数学课做一个项目,我选择了旅行推销员问题,这是我一直想调查的问题。 然而,我的暴力解决算法有问题 *请转到底部的更新以查看代码的最新版本 如果你知道旅行推销员的问题是什么,就跳过这一段: 尽可能概括地说,TSP是这样的:你是一个推销员,想要访问一个地区的每个城市(一个城市本质上是地图上的一个点)。在有边界的x和y区域中有“n”个城市,每个城市都与每个城市相连(假设有一条直路)。你需要在所有城市中找到最短的路线,以便访问每个城市。我想使用的算法之一(我需要测试其他算法)是蛮力算法

我正在为学校的数学课做一个项目,我选择了旅行推销员问题,这是我一直想调查的问题。 然而,我的暴力解决算法有问题

*请转到底部的更新以查看代码的最新版本



如果你知道旅行推销员的问题是什么,就跳过这一段: 尽可能概括地说,TSP是这样的:你是一个推销员,想要访问一个地区的每个城市(一个城市本质上是地图上的一个点)。在有边界的x和y区域中有“n”个城市,每个城市都与每个城市相连(假设有一条直路)。你需要在所有城市中找到最短的路线,以便访问每个城市。我想使用的算法之一(我需要测试其他算法)是蛮力算法,它检查所有可能的路线并返回最短路线。之所以不总是使用此选项,是因为它要求我们检查(n-1)!可能的路线,而且随着“n”的增加,这个数字变得越来越大——事实上,只有50个城市,这将是60828186403426756087225213321295376887552831792102400000000000条要检查的路线

假设在本文讨论的所有示例中,我们将使用一个包含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");

    }
public void BruteForceFindBestRoute(路由r)//必须从r开始,并从1个无障碍城市开始
{
如果(!r.allFlagged()&&r.route.size()!=m.cities.size())
{
/*第1步从最后一个无障碍城市开始*/
城市轴=r.lastCityAdded();
/*第二步:旗城*/
pivot.visted=true;
/*步骤3:查找“不在路线中”的城市*/
ArrayList citiesNotInRoute=新的ArrayList();

对于(int i=0;i,在递归调用返回后,您应该从路由中删除城市。您可以执行以下操作:

            Route newRoute = r;
            newRoute.addToRoute(citiesNotInRoute.get(i));
            BruteForceFindBestRoute(newRoute);
但决不能使用
新建路由。从路由中删除
或类似的路由

请注意,您正在编写Java,而在Java中,对象的赋值是通过引用完成的。这意味着
r
newRoute
是同一个对象。
newRoute
并不像您预期的那样是
r
的独立副本。因此对
newRoute
的任何修改也将改变
r
。您可以可能需要在那里明确复制路由。Java术语是。确保克隆足够深,即克隆所有相关数据结构,而不是在原始数据结构和克隆数据结构之间共享它们

注意:有很多地方可以让你的代码更高效,但是在任何情况下,蛮力都是远远不够的,你只会谈论很少的城市,也许你不必在意。但是,如果你想研究替代方案,考虑一下保持所有未访问城市的单链表。帽子列表,删除元素,递归并放回元素。无需在每次调用中从头开始构建此列表。的思想可以灵活地应用于此任务,作为预制链表实现的替代方案

编辑:

您的代码的以下变体适用于我:

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);
    }
}
import java.util.*;
SO11703827类{
私有静态数组列表最佳路径;
公共静态无效bruteForceFindBestRoute
(ArrayList r,
ArrayList citiesNotInRoute)
{
如果(!citiesNotInRoute.isEmpty())
{

对于(int i=0;这正是我想要做的——但是当递归调用返回时,我的路由(称为r)中的每个城市都在其中,这是我不理解的。我希望在第一个递归调用的第一次返回时,我会得到类似于r=[Af,Bf,C]的东西。然后在第一个递归调用的第二次返回时,r=[Af,B]然而,我在第一次递归调用的第一次返回时得到了这个结果:r=[Af,Bf,Cf,Df]这没有意义。如果我不清楚,请告诉我,我可以试着重新解释。谢谢你的快速回复。嗯,我可能会尝试你的链接列表想法。我将不得不考虑一下,但这听起来像是一个不错的替代方案。我一直在干扰我的第一个实现想法,6个多小时都没有用,所以我对n持开放态度新想法。@Matt,我的答案似乎不够清楚。我想我错过了你困惑的主要原因。现在编辑代码以指出共享对象。好的,我已经编写了正确的克隆()方法,我重新编写了蛮力方法以利用这些方法。它仍然不起作用。我重新编写了蛮力方法,试图使其更简单-请再次查看操作以查看底部的更新代码。再次感谢,我真的非常感谢您的帮助。希望这次更容易阅读Matt@Matt,您使用数组列表作为循环缓冲区的方式让我困惑了一会儿,但应该可以。一个
ArrayDeque
将是该列表的更好实现,但这只与性能有关。克隆城市应该是不必要的。除此之外,事情对我来说是可行的,所以我假设t有问题他是你实现克隆的方式。@nhgrif是的,这个问题已经得到了回答,代码确实有效。问题在于我实现的“克隆”,这里甚至没有显示;在“更新”之后的暴力算法确实有效,因为它是
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);
    }
}