正如评论所暗示的,您的问题与旅行推销员问题有关。它实际上是哈密顿路径的一个例子(一条访问每个节点一次的路径,但不会在它开始的地方结束)。如您所料,在 R 中已经有一个包:TSP
. 看到这个和这个。
旅行商问题非常难以准确解决(在合理的时间内),因此大多数算法都是近似的和迭代的:它们使用“可能”产生短路径的算法从随机起点探索各种路径,但不一定是绝对最短的。
在您的示例中,只有 10 个节点,可以执行穷举(蛮力)搜索。这很有用,因为我们可以将近似 TSP 解决方案与精确解决方案进行比较。但是请注意,即使只有 10 个节点,蛮力方法也需要检查约 360 万条路径,大约需要 2 分钟。对于 20 个节点,路径数约为 2.5 × 10 18。
# Hamiltonian Path via traveling salesman problem
library(TSP)
tsp <- TSP(dist(df))
tsp <- insert_dummy(tsp, label = "cut")
tour <- solve_TSP(tsp, method="2-opt", control=list(rep=10))
path.tsp <- unname(cut_tour(tour, "cut"))
path.tsp
# [1] 6 3 5 4 8 2 1 10 7 9
# Hamiltonian Path via brute force
library(combinat)
M <- as.matrix(dist(df)) # distance matrix
paths <- permn(nrow(M)) # all possible paths (~ 3.6e6 !!!)
lengths <- sapply(paths,function(p)sum(M[cbind(p[-nrow(M)],p[-1])]))
path.bf <- paths[[which.min(lengths)]]
path.bf
# [1] 9 7 10 1 2 8 4 5 3 6
# plot the results
par(mfrow=c(1,2))
plot(Y~X,df[s.path.tsp,],type="b",asp=1)
plot(Y~X,df[s.path.bf,],type="b",asp=1)
要将 TSP 问题转换为哈密顿路径问题,我们必须添加一个“虚拟顶点”,它与每个其他节点的距离为 0(参见上面引用的小插图)。然后,哈密顿路径是从虚拟节点之后的节点开始到虚拟节点之前的节点结束的 TSP 路径。
请注意,蛮力和 TSP 解决方案标识完全相同的路径,但顺序相反。这是因为,当然,两条路径具有相同的长度。