1、问题分析
目的:在旅行商问题的基础上,无需返回起点。相当于找到一条最短路径,能够遍历所有的顶点。起点和终点都是动态计算出来的,不是提前固定的。
这个问题也称为为计算“最短的哈密尔顿路径”。
2、解决方案
出处:What is the problem name for Traveling salesman problem(TSP) without considering going back to starting point?
解决方案1(起点终点都不提前固定)
我在这本书中找到了我问题的答案。在计算机和其他数字系统的设计中反复出现的计算机布线问题也是如此。目的是尽量减少电线的总长度。因此,它确实是一条最小长度的哈密顿路径。
这本书建议创建一个虚拟点,其与其他点的距离为0。因此,该问题变成了(n+1)个城市对称TSP。求解后,只需删除虚拟点,然后求解最小长度哈密顿路径,我们就可以在不返回起点的情况下得到TSP路径。
解决方案2(需要固定起点和终点):
关于起点和终点的问题描述:
当我们通过TSP得到解并删除虚拟节点时,哈密顿路径的起点变为虚拟节点之后的节点,终点变为虚拟点之前的节点?这是正确的吗?此外,如果我们想确定起点,我们如何使用这种技术或其他技术来实现?
回答:
可以通过创建一个虚拟点来固定起点和终点,该虚拟点与起点和终点的距离均为0,与所有其他点的距离为无限。这将需要n次迭代来解决整个问题。请参考:How to fix the start and end points in Travelling Salesmen Problem?。
解决方案3(关于TSP问题的近似值)
如果我理解正确,你想找到最短路径(从一些顶点开始),穿过图中的所有节点,而不访问同一个节点两次。一个更简单的问题是哈密顿路径问题。正如你所说,它问是否存在这样的路径。既然这个问题是NP难的,而且它比你的问题更容易,那么解决你的问题至少是NP难。好吧,这不是真的,因为你的问题不是决策问题。但它所说的是,我们几乎可以肯定,你的问题没有多项式算法。
你可以求助于近似值。这里有一个非常酷的TSP度量近似值:
http://en.wikipedia.org/wiki/Travelling_salesman_problem#Metric_TSP
其他参考
https://or.stackexchange.com/questions/6174/travelling-salesman-problem-variant-without-returning-to-the-starting-point
https://math.stackexchange.com/questions/603540/traveling-salesman-with-pairs-of-cities-without-return-and-with-given-start-and
https://or.stackexchange.com/questions/6174/travelling-salesman-problem-variant-without-returning-to-the-starting-point
https://cs.stackexchange.com/questions/43549/what-tsp-variant-doesnt-return-to-start-point
3、示例代码及示意图
共同的工具方法参考:关于使用QuikGraph库进行TSP求解
主要测试代码:
public void Test2(){var vertexs = new string[]{"A", "B", "C", "D", "E", "F", "G", "H"};AddVertex("Start");//增加虚拟点foreach (var v in vertexs){AddVertex(v);AddEdge("Start", v, 0);//虚拟点到其他顶点的距离设置为0}AddEdge("A", "B");AddEdge("B", "C");AddEdge("C", "D");AddEdge("C", "E");AddEdge("C", "F", 2);AddEdge("D", "E");AddEdge("F", "E");AddEdge("G", "E", 2);AddEdge("F", "G");AddEdge("H", "G"); var tsp = new TSP<string, EquatableEdge<string>, BidirectionalGraph<string, EquatableEdge<string>>>(_graph, GetWeightsFunc()); tsp.Compute();var r = tsp.ResultPath;if (r == null){Console.WriteLine("无解");return;}//连成一条路径var dict = r.Edges.ToDictionary(x => x.Source, x => x.Target);var start = dict.Keys.First();var cur = start;var pathVertexs = new List<string>();while (dict.TryGetValue(cur, out string next) && next != start){cur = next;pathVertexs.Add(next);}Console.WriteLine($"Path={string.Join("->", pathVertexs)}");Console.WriteLine($"Cost={tsp.BestCost}");}
控制台输出结果:
Path=H->G->F->E->D->C->B->A
Cost=7
输入数据示意图:
计算结果: