使用Java中的动态编程解决TSP问题

时间:2015-10-30 10:07:25

标签: java algorithm dynamic-programming traveling-salesman

我在网上找到了很多资源,讨论了这个问题和相关主题,但我还没有找到任何真正帮助我知道从何处开始实施此解决方案的资源。

澄清一下,从0号城市开始,我需要访问其他所有城市一次,然后返回0城市。

我有一个像这样的数组:

   0 1129 1417 1240 1951
1129    0 1100  800 2237
1417 1100    0 1890 3046
1240  800 1890    0 1558
1951 2237 3046 1558    0

在找到最佳路线的同时,我还需要找到最佳的部分路线。例如,我从长度为2的路线开始,最后打印出类似这样的东西:

S = {0,1}
C({0,1},1) = 1129

S = {0,2}
C({0,2},2) = 1417

S = {0,3}
C({0,3},3) = 1240

S = {0,4}
C({0,4},4) = 1951

然后我会去长度为3的路线,打印出这样的东西:

S = {0,1,2}
C({0,1,2},1) = 2517
C({0,1,2},2) = 2229
and so on...

为了使这成为一个动态编程解决方案,我假设我应该保存任意n个节点之间的最短距离,而我认为这样做的最好方法是使用Hashmap,其中键是一个整数该路径中包括的每个节点的值按升序排列(从节点0> 1> 3> 4或0> 1> 4> 3的路径可以存储为' 134'),并且每个密钥将保持一对可以将路径顺序存储为List,并将总距离存储为整数。

此时我认为我想要计算距离2的所有路径,然后计算所有距离3,然后取最小的几个并使用hashmap找回每个路径的最短路径,并进行比较

这看起来好像可以吗?还是我完全走错了路?

2 个答案:

答案 0 :(得分:1)

你正在走上正轨。动态编程不是计算TSP的方法。您接近的是计算最小生成树。这是一棵树,使用尽可能短的边缘连接所有节点。经常使用两种算法:Primm和Kruskal。它们产生类似于最佳部分路线列表的东西。我建议你看看Primm的算法:https://en.wikipedia.org/wiki/Prim%27s_algorithm

解决TSP的最简单方法是找到最小生成树,然后在树上执行预订树遍历。这为您提供了近似的旅行推销员解决方案,被称为三角不等式近似。它保证不会超过最佳TSP的两倍,但可以更快地计算出来。这个网页很好地解释了http://www.personal.kent.edu/~rmuhamma/Algorithms/MyAlgorithms/AproxAlgor/TSP/tsp.htm

如果你想要一个更优化的解决方案,你需要看看Christofide的方法,这个方法更复杂。

答案 1 :(得分:1)

你走在正确的轨道上。

我认为你已经意识到DP递归本身只告诉你每个S和j的最优成本,而不是那个达到这个成本的节点 。处理这种情况的经典方法是通过“回溯”:一旦你发现了这一点,例如,C({0,1,2,3,4},-) = 10000,你就会发现哪个节点达到了这个成本;让我们说它是3.然后你找出哪个节点达到C({0,1,2,3,4},3);让我们说它是1.然后你找出哪个节点达到C({0,1,2,4},1);让我们说它是2,......等等。这是经典的方法,它避免了必须存储大量的中间数据。对于具有小状态空间的DP,在此过程中存储所有这些优化器会更容易。在您的情况下,您有一个指数级大的状态空间,因此存储所有这些优化器可能会很昂贵,但您必须存储一个同样大的数据结构(C),因此很可能您可以将优化器存储为好。你存储一些最好的中间解决方案可以工作 - 然后如果回溯例程需要一个你没有存储的你可以用经典的方式计算它 - 似乎合理,但我不确定它是否值得额外编码与纯回溯方法。

一个澄清:你实际上并不想“计算距离2的所有路径,然后计算所有距离3,...”,而是想要枚举大小为2的所有 ,然后所有设置大小为3,等等。仍然是指数级的,但没有枚举所有路径那么糟糕。