library(tidyverse)

Initialize Data

max_color <- 4
m <- matrix(c(1,2,2,1,3,4,1,3,3,5,5,5),3)
print(m)
##      [,1] [,2] [,3] [,4]
## [1,]    1    1    1    5
## [2,]    2    3    3    5
## [3,]    2    4    3    5
cbind(expand.grid(row = 1:3, col = 1:4), house = as.vector(m)) %>%
  ggplot(aes(col, desc(row))) +
  geom_tile(aes(fill=as.factor(house))) +
  geom_text(aes(label = house)) +
  guides(fill = FALSE)

Enumerate All Adjacent Pairs

adjacent <- rbind(tibble(A = as.vector(m[-nrow(m),]),  # rows: 1 ~ (nrow-1)
                         B = as.vector(m[-1,])),       # rows: 2 ~ nrow
                  tibble(A = as.vector(m[,-ncol(m)]),  # cols: 1 ~ (ncol-1)
                         B = as.vector(m[,-1])))       # cols: 2 ~ ncol
adjacent <- adjacent %>%
  filter(A != B) %>%
  unique

Check All Combinations

all_comb <- function(n) {
  if (n <= 1) {
    lapply(1:max_color, function(x) tibble(house = 1, fill = x))
  } else {
    l <- all_comb(n - 1)
    lapply(1:max_color, function(x) {
      lapply(l, function(d) rbind(d, tibble(house = n, fill = x)))
    }) %>% do.call("c", .)
  }
}

x <- unique(as.vector(m))
comb <- all_comb(length(x))
results <- sapply(comb, function(d) {
  adjacent %>%
    left_join(d, by = c("A" = "house")) %>%
    left_join(d, by = c("B" = "house")) %>%
    with(all(fill.x != fill.y &                                 # different color in adjacent houses
               length(unique(c(fill.x, fill.y))) == max_color)) # total four colors
})

Final results:

print(sum(results))
## [1] 72

Show Results

for (i in which(results)) {
  g <- cbind(expand.grid(row = 1:3, col = 1:4), house = as.vector(m)) %>%
    left_join(comb[[i]], by = "house") %>%
    ggplot(aes(col, desc(row))) +
    geom_tile(aes(fill=as.factor(fill))) +
    geom_text(aes(label = fill)) +
    guides(fill = FALSE)
  print(g)
}