【问题标题】:How to find all possible "continuous" paths of a matrix / network / graph in R如何在 R 中找到矩阵/网络/图形的所有可能的“连续”路径
【发布时间】:2020-04-30 13:10:08
【问题描述】:

我有兴趣确定 R 中 NxN 矩阵的所有可能“连续”路径并返回它们的结果。 “连续”是指我们可以在不举起铅笔/数字的情况下旅行。也就是说,我们可以向上、向下、向左、向右或沿对角线移动。

为了具体说明,让我们使用一个 3x3 矩阵示例:

mat_3x3 <- matrix(LETTERS[1:9], ncol = 3, byrow = TRUE)
mat_3x3
#      [,1] [,2] [,3]
# [1,] "A"  "B"  "C" 
# [2,] "D"  "E"  "F" 
# [3,] "G"  "H"  "I" 

这意味着我们有以下有效和无效的路径:

一些注意事项:

  • 起始位置不必是位置A (1, 1)。
  • 我们不能“双退”或多次触摸同一个单元格。
  • 短路径是可能的(例如,A -&gt; B -&gt; C 是有效路径;同样,A -&gt; E -&gt; I)——也就是说,我们不需要通过所有节点。

如果有方便的包或概念,请指教(我见过的图遍历包大部分都是“图”而不是“矩阵”)。我想动态编程或递归可能在这里有用,但我不知道如何开始。


我相信对于路径 = 15 的一个单元格,对于以下解决方案,2X2 案例的答案可能是 60; 15 * 4 = 60:

但是,对于 3x3、4x4 的情况,情况会迅速升级...不再只是角落,添加“中心”正方形等...


如果我们将这个问题更多地考虑为一个图或网络,那么对于 3X3 情况,我们有以下内容:

为什么? 我只是对这个问题真正感兴趣并且觉得它很有趣。我想了解如何在R 中对其进行编程,但如果存在其他答案,我会考虑(然后可能将它们转换为R)。它最初是一个思考“游戏”的思想实验,您可以在触摸屏上滑动手指以从字符串中创建单词。我们想要最大化分数而不是最小成本——使用ZE 得分更高,例如Scrabble 等。但我想这在社交网络、图论、交通方面有有趣的应用优化和其他领域。

【问题讨论】:

  • 您可以构建一个看起来像矩阵的图形。这是 Python 中的一个 example
  • 我会首先尝试找出一个合适的算法,然后担心如何在 R 中实现它。谷歌搜索“查找所有路径网格”似乎是一个合理的开始,尽管它们中的大多数都是为查找两个特定节点之间的路径而设计的,而不是查找覆盖网格中每个节点的所有路径...
  • 我同意 Ben 的观点,首先找到合适的方法很重要。但是,假设每个节点都是唯一的 id,我认为combinat::permn(m) 将为您提供每个可能遍历节点的节点顺序。不过,9 个节点会产生 362,880 (factorial(9)) 个排列,所以现在您遇到了如何处理这些排列的问题。
  • 这里有一个解决方案,虽然它不在 R stackoverflow.com/questions/13410168/…
  • 哦,我认为路径必须通过所有节点......你的用例是什么?你打算用多大的网格来试试这个……?

标签: r matrix igraph graph-theory


【解决方案1】:

这将适用于任何大小的矩阵(受硬件限制),并且不需要矩阵是矩形的,例如3 x 4。它构建了一个有效矩阵,该矩阵将所有原始矩阵位置作为列,如果是有效移动,则该行将返回TRUE,如果不是,则返回FALSE。我没有验证所有结果,但我所做的抽查工作。

library(gtools)

# convert matrix to numbers to reference by position
m <- matrix(seq_along(mat_3x3), ncol = ncol(mat_3x3))

# create blank matrix that is used to see if it is a valid move
mLength <- length(m)
mValid <- matrix(rep(FALSE, mLength ^ 2), ncol = mLength)

# create index to generate validity matrix
xIndex <- seq_len(ncol(m))
yIndex <- seq_len(nrow(m))

# wrap with NA to prevent out of bounds
mBounds <- rbind(NA, cbind(NA, m, NA), NA)

# set validity matrix TRUE if returns a value that is not NA
mValid[cbind(as.vector(mBounds[yIndex + 1, xIndex + 2]), seq_len(mLength))] <- TRUE
mValid[cbind(as.vector(mBounds[yIndex + 2, xIndex + 2]), seq_len(mLength))] <- TRUE
mValid[cbind(as.vector(mBounds[yIndex + 2, xIndex + 1]), seq_len(mLength))] <- TRUE
mValid[cbind(as.vector(mBounds[yIndex + 2, xIndex    ]), seq_len(mLength))] <- TRUE
mValid[cbind(as.vector(mBounds[yIndex + 1, xIndex    ]), seq_len(mLength))] <- TRUE
mValid[cbind(as.vector(mBounds[yIndex    , xIndex    ]), seq_len(mLength))] <- TRUE
mValid[cbind(as.vector(mBounds[yIndex    , xIndex + 1]), seq_len(mLength))] <- TRUE
mValid[cbind(as.vector(mBounds[yIndex    , xIndex + 2]), seq_len(mLength))] <- TRUE

# define function to check if provided sequence is valid
validate <- function(x) {
  all(mValid[cbind(x[-1], x[-length(x)])])
}

# generate all permutations
p1 <- permutations(mLength, mLength)
p2 <- apply(p1, 1, validate)
p2 <- p1[p2, ]

# some results
> mat_3x3[p2[1, ]]
[1] "A" "D" "G" "E" "B" "C" "F" "H" "I"

> mat_3x3[p2[531, ]]
[1] "C" "E" "H" "G" "D" "A" "B" "F" "I"

要生成不使用所有字母的其他序列,需要更改上面的permutations 函数以限制目标向量长度:

p1 <- permutations(mLength, mLength - 1)
p2 <- apply(p1, 1, validate)
p2 <- p1[p2, ]

> mat_3x3[p2[1701, ]]
[1] "C" "F" "B" "D" "G" "E" "I" "H"

在构建排列时使用combinat::permn 来使用validate 函数。

library(combinat)
p <- list()
pTemp <- permn(mLength, function(x) x[validate(x)])
p[[mLength]] <- pTemp[lengths(pTemp) > 0]

# breaking all paths that use every option into smaller pieces to find shorter paths
for (i in seq_len(mLength)[-mLength]) {
  pTemp <- lapply(p[[mLength]], function(x, y) embed(rev(x), length(x) - y), y = i)
  p[[mLength - i]] <- unique(do.call(rbind, pTemp))
}

# total number of paths
sum(unlist(lapply(p, nrow)), length(p[[mLength]]))

【讨论】:

  • 我喜欢这个。我想知道是否可以利用combinat::permn 而不是gtools::permutations 来“即时”执行validate 功能
  • @JasonAizkalns 更新为使用 combinat::permn 和所有较短的路径。但是,可能需要一种更好的方法来构建排列,因为增加矩阵大小会很快达到内存限制。
  • 谢谢。我发布了this related question,这可能会提供一些线索/想法。我还没有时间深入挖掘。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-11-03
  • 2023-04-05
  • 1970-01-01
  • 2017-05-06
相关资源
最近更新 更多