Поиск шаблона в бинарной матрице с помощью R

У меня есть симметричная двоичная матрица nxn, и я хочу найти самый большой прямоугольник (площадь) с 0 в верхнем левом и нижнем правом углах и 1 в верхнем правом и нижнем левом углах. Если я просто делаю это с помощью циклов, проверяя все прямоугольники от самого большого до самого маленького, это занимает «дни» для n=100. У кого-нибудь есть идея сделать это эффективно?

Большое спасибо !

2 ответа

спасибо за ваши ответы. Я использую матрицы смежности случайных графов Эрдоша-Реньи. Но для проверки можно взять любую случайную симметричную бинарную матрицу. До сих пор я использую 4 вложенных цикла:

      switch<-function(Mat)
{
n=nrow(Mat) 
for (i in 1:(n-1)) { 
    for(j in seq(n,i+1,by=-1)) {
        for(k in 1:(n-1)) { 
            if ((k==i)||(k==j) || (Mat[i,k]==1)||(Mat[j,k]==0)) next 
            for(l in seq(n,k+1,by=-1)) { 
                if ((l==i)||(l==j)|| (Mat[i,l]==0)||(Mat[j,l]==1)) next 
                return(i,j,k,l)
            }
        }
    }
}

Вот подход, который вы можете попробовать прямо сейчас. Он не требует симметрии и для эффективности рассматривает все ненулевые элементы как единицы.

Он перебирает единицы, предполагая, что единиц меньше, чем нулей. (В обратном случае вы хотели бы перебирать нули с меньшим количеством нулей, чем единиц.)

Этот подход, вероятно, не оптимален, поскольку он зацикливается на всех единицах, даже если самый большой ящик идентифицируется заранее. В этом случае вы можете придумать умное условие остановки, чтобы замкнуть контур. Но это все еще быстро для n = 100, на моей машине требуется менее половины секунды, даже если единицы и нули встречаются примерно в равной пропорции (наихудший случай):

      f <- function(X) {
    if (!is.logical(X)) {
        storage.mode(X) <- "logical"
    }
    J <- which(X, arr.ind = TRUE, useNames = FALSE)
    i <- J[, 1L]
    j <- J[, 2L]
    nmax <- 0L
    res <- NULL
    for (k in seq_along(i)) {
        i0 <- i[k]
        j0 <- j[k]
        ok <- i < i0 & j > j0
        if (any(ok)) {
            i1 <- i[ok]
            j1 <- j[ok]
            ok <- !(X[i0, j1] | X[i1, j0])
            if (any(ok)) {
                i1 <- i1[ok]
                j1 <- j1[ok]
                n <- (i0 - i1 + 1L) * (j1 - j0 + 1L)
                w <- which.max(n)
                if (n[w] > nmax) {
                    nmax <- n[w]
                    res <- c(i0 = i0, j0 = j0, i1 = i1[w], j1 = j1[w])
                }
            }
        }
    }
    res
}
      mkX <- function(n) {
    X <- matrix(sample(0:1, n * n, TRUE), n, n)
    X[upper.tri(X)] <- t(X)[upper.tri(X)]
    X
}

set.seed(1L)
X <- mkX(6L)
X
##      [,1] [,2] [,3] [,4] [,5] [,6]
## [1,]    0    1    0    0    1    0
## [2,]    1    0    1    1    0    0
## [3,]    0    1    0    1    1    1
## [4,]    0    1    1    0    0    0
## [5,]    1    0    1    0    0    1
## [6,]    0    0    1    0    1    0

f(X)
## i0 j0 i1 j1 
##  5  1  1  5 
      Y <- mkX(100L)
microbenchmark::microbenchmark(f(Y))
## Unit: milliseconds
##  expr     min       lq     mean   median       uq      max neval
##  f(Y) 310.139 318.3363 327.8116 321.4109 326.5088 391.9081   100
Другие вопросы по тегам