How do I get the shortest route in a labyrinth?

别来无恙 提交于 2019-12-05 17:24:22

You could construct a graph to represent the valid moves between positions in the matrix:

# Construct nodes and edges from matrix
(nodes <- which(m == 1 | m == 2 | m == 3, arr.ind=TRUE))
#       row col
#  [1,]   1   1
#  [2,]   2   1
#  [3,]   4   1
#  [4,]   2   2
#  [5,]   3   2
#  [6,]   4   2
#  [7,]   4   3
#  [8,]   2   4
#  [9,]   4   4
edges <- which(outer(seq_len(nrow(nodes)),seq_len(nrow(nodes)), function(x, y) abs(nodes[x,"row"] - nodes[y,"row"]) + abs(nodes[x,"col"] - nodes[y,"col"]) == 1), arr.ind=T)
(edges <- edges[edges[,"col"] > edges[,"row"],])
#      row col
# [1,]   1   2
# [2,]   2   4
# [3,]   4   5
# [4,]   3   6
# [5,]   5   6
# [6,]   6   7
# [7,]   7   9

library(igraph)
g <- graph.data.frame(edges, directed=FALSE, vertices=seq_len(nrow(nodes)))

Then you could solve the shortest path problem between the specified start and end location:

start.pos <- which(m == 2, arr.ind=TRUE)
start.node <- which(paste(nodes[,"row"], nodes[,"col"]) == paste(start.pos[,"row"], start.pos[,"col"]))
end.pos <- which(m == 3, arr.ind=TRUE)
end.node <- which(paste(nodes[,"row"], nodes[,"col"]) == paste(end.pos[,"row"], end.pos[,"col"]))
(sp <- nodes[get.shortest.paths(g, start.node, end.node)$vpath[[1]],])
#      row col
# [1,]   1   1
# [2,]   2   1
# [3,]   2   2
# [4,]   3   2
# [5,]   4   2
# [6,]   4   3
# [7,]   4   4

Finally, you could determine the direction (1: east; 2: north; 3: west; 4: south) as a simple manipulation of the final set of nodes selected:

dx <- diff(sp[,"col"])
dy <- -diff(sp[,"row"])
(dirs <- ifelse(dx == 1, 1, ifelse(dy == 1, 2, ifelse(dx == -1, 3, 4))))
# [1] 4 1 4 4 1 1

This code will work for arbitrarily sized input matrices.

Data:

(m <- matrix(c(2, 1, 0, 1, 0, 1, 1, 1, 0, 0, 0, 1, 0, 1, 0, 3), nrow=4))
#      [,1] [,2] [,3] [,4]
# [1,]    2    0    0    0
# [2,]    1    1    0    1
# [3,]    0    1    0    0
# [4,]    1    1    1    3
Josh O'Brien

I'd likely use functions from the gdistance package, demonstrated in another setting here:

library(gdistance) ## A package to "calculate distances and routes on geographic grids"

## Convert sample matrix to a spatial raster
m = matrix(c(2, 1, 0, 1, 0, 1, 1, 1, 0, 0, 0, 1, 0, 1, 0, 3), nrow=4)
R <- raster(m)

## Convert start & end points to SpatialPoints objects
startPt <- SpatialPoints(xyFromCell(R, Which(R==2, cells=TRUE)))
endPt   <- SpatialPoints(xyFromCell(R, Which(R==3, cells=TRUE)))

## Find the shortest path between them
## (Note: gdistance requires that you 1st prepare a sparse "transition matrix"
##  whose values give the "conductance" of movement between pairs of cells)
tr1 <- transition(R, transitionFunction=mean, directions=4)
SPath <- shortestPath(tr1, startPt, endPt, output="SpatialLines")

## Extract your direction codes from the steps taken in getting from 
## one point to the other. 
## (Obfuscated, but it works. Use some other method if you prefer.)
steps <- sign(diff(coordinates(SPath)[[1]][[1]]))
(t(-steps)+c(2,3))[t(steps!=0)]
## [1] 4 1 4 4 1 1

## Graphical check that this works
plot(R>0)
plot(rBind(startPt, endPt), col=c("yellow", "orange"), pch=16, cex=2, add=TRUE)
plot(SPath, col="red", lwd=2, add=TRUE)

One possibility consists in setting up a matrix with value 1 at the target and a decrease of the value at the rate of 0.9 for each square, as a function of the Manhattan distance from the destination. The obstacles would have the value zero, the starting point is arbitrary.

Once such a matrix is defined, the shortest path is obtained by iteratively going to the neighboring square with the largest increase in value.

This method is described, e.g., in the first chapter of the book "Statistical Reinforcement Learning" by M. Sugiyama.

So your matrix could look like this:

     [,1]  [,2]  [,3] [,4]
[1,] 0.53  0.00  0.0  0.00
[2,] 0.59  0.66  0.0  0.81
[3,] 0.00  0.73  0.0  0.00
[4,] 0.73  0.81  0.9  1.00

And the algorithm would be:

  • Choose a starting square with non-zero value
  • Move to the square that has the highest value among those squares that are one step away from you.
  • Repeat the previous step until you reach the square with value 1

Note that the value [2,4] is de facto not accessible and should therefore be excluded as a possible starting point. The destination does not need to be at a corner.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!