Longitud del descenso más largo

8

Su tarea es determinar la longitud del descenso más largo por una "montaña" representada como una cuadrícula de alturas enteras. Un "descenso" es cualquier camino desde una celda inicial a celdas adyacentes ortogonalmente con alturas estrictamente decrecientes (es decir, no diagonal y no a la misma altura). Por ejemplo, puede pasar de 5-4-3-1 pero no 5-5-4-3-3-2-1. La longitud de esta ruta es cuántos movimientos de celda hay desde la celda inicial hasta la celda final, por lo tanto, 5-4-3-1 es la longitud 3.

Recibirá una cuadrícula rectangular como entrada y debería generar un número entero que indique el descenso más largo.

Ejemplos

1 2 3 2 2
3 4 5 5 5
3 4 6 7 4
3 3 5 6 2
1 1 2 3 1

La longitud del descenso más largo por esta montaña es 5. El camino más largo comienza en el 7, se mueve hacia la izquierda, arriba, izquierda, arriba y luego a la izquierda (7-6-5-4-2-1). Como hay 5 movimientos en esta ruta, la longitud de la ruta es 5.

Pueden ser todos el mismo número.

1 1 1 1 1
1 1 1 1 1
1 1 1 1 1
1 1 1 1 1

Como este mapa de altura es plano, el descenso más largo es 0. (no 19, ya que la secuencia de la ruta debe ser estrictamente descendente)

Los mapas de altura pueden estar formados por números más grandes que los números de un solo dígito.

10 12 13 14 15 15
17 14 15 15 15 16
18 20 21 15 15 15
21 14 10 11 11 15
15 15 15 15 15 15

El camino más largo aquí es de longitud 6. (21, 20, 18, 17, 14, 12, 10)

... e incluso números más grandes también están bien.

949858 789874  57848  43758 387348
  5848 454115   4548 448545 216464
188452 484126 484216 786654 145451
189465 474566 156665 132645 456651
985464  94849 151654 151648 484364

El descenso más largo aquí es de longitud 7. (786654, 484216, 484126, 474566, 156665, 151654, 151648, 132645)

Reglas y notas

  • Las cuadrículas se pueden tomar en cualquier formato conveniente. Especifique su formato en su respuesta.
  • Puede suponer que el mapa de altura es perfectamente rectangular, no está vacío y contiene solo enteros positivos en el rango de enteros de 32 bits con signo.
  • El camino de descenso más largo puede comenzar y terminar en cualquier lugar de la cuadrícula.
  • No necesita describir el camino de descenso más largo de ninguna manera. Solo se requiere su longitud.
  • El código más corto gana
Carne de res
fuente
¿Cómo debe interpretarse el último ejemplo?
Peter Taylor
@PeterTaylor No estoy seguro de lo que quieres decir.
Beefster
Creo que el último ejemplo es solo una matriz de números de varios dígitos
encarnación de la ignorancia el
@EmbodimentofIgnorance, ah, sí, ya veo. Sería mucho más fácil detectar el camino con números de dos dígitos en lugar de 4 a 6.
Peter Taylor
1
@ Οurous: solo rectangular. No irregular.
Beefster

Respuestas:

8

JavaScript (ES7),  106 103 102  98 bytes

f=(m,n=b=-1,x,y,p)=>m.map((r,Y)=>r.map((v,X)=>(x-X)**2+(y-Y)**2-1|v/p?b=n<b?b:n:f(m,n+1,X,Y,v)))|b

Pruébalo en línea!

Comentado

f = (                        // f = recursive function taking:
  m,                         //   m[]  = input matrix
  n = b = -1,                //   n    = length of the current path; b = best length so far
  x, y,                      //   x, y = coordinates of the previous cell
  p                          //   p    = value of the previous cell
) =>                         //
  m.map((r, Y) =>            // for each row r[] at position Y in m[]:
    r.map((v, X) =>          //   for each value v at position X in r[]:
      (x - X) ** 2 +         //     compute the squared Euclidean distance
      (y - Y) ** 2           //     between (x, y) and (X, Y)
      - 1                    //     if A) the above result is not equal to 1
      | v / p ?              //     or B) v is greater than or equal to p:
        b = n < b ? b : n    //       end of path: update b to n if n >= b
      :                      //     else:
        f(m, n + 1, X, Y, v) //       do a recursive call
    )                        //   end of inner map()
  ) | b                      // end of outer map(); return b

¿Cómo?

Durante la primera iteración, , y están todos indefinidos y ambas pruebas ( A y B en los comentarios) evalúan a NaN , lo que desencadena la llamada recursiva. Por lo tanto, todas las celdas se consideran como un posible punto de partida de la ruta.xyp

Arnauld
fuente
6

Gelatina ,  23 21  20 bytes

-2 gracias a Erik the Outgolfer

ŒỤŒPạƝ§ỊẠƲƇœị⁸QƑƇṪL’

Pruébalo en línea! (Demasiado ineficiente para los ejemplos: la ruta aquí es95 94 93 83 77 40 10así que se6produce)

¿Cómo?

ŒỤŒPạƝ§ỊẠƲƇœị⁸QƑƇṪL’ - Link: list of lists of integers, M
ŒỤ                   - multi-dimensional indices sorted by values
  ŒP                 - power-set
          Ƈ          - filter, keep those for which:
         Ʋ           -   last four links as a monad:
     Ɲ               -     for each pair of neighbours:
    ạ                -       absolute difference
      §              -     sum each
       Ị             -     insignificant?
        Ạ            -     all?
           œị        - multi-dimensional index into:
             ⁸       -   chain's left argument, M
                Ƈ    - filter, keep only those:
               Ƒ     -   unaffected by?:
              Q      -     de-duplicate
                 Ṫ   - tail
                  L  - length
                   ’ - decrement
Jonathan Allan
fuente
3

Python 2, 150 147 140 136 134 132 125 123 120 bytes

l=lambda g,i,j:max(0<g.get(t)<g[i,j]and-~l(g,*t)for d in(-1,1)for t in((i+d,j),(i,j+d)))
lambda g:max(l(g,*t)for t in g)

Pruébalo en línea!

Toma entrada en forma de diccionario (x, y): value.

-7 bytes gracias a wizzwizz4, -2 bytes gracias a Jonathan Allen, -2 bytes gracias a BMO

Alternativa, 123 121 bytes

l=lambda i,j:max(0<g.get(t)<g[i,j]and-~l(*t)for d in(-1,1)for t in((i+d,j),(i,j+d)))
g=input();print max(l(*t)for t in g)

Pruébalo en línea!

Esencialmente, la misma solución, solo con el lambda final reemplazado por un programa real. Personalmente, me gusta más el primero, pero este se acerca al recuento de bytes al permitir gque se use como una variable global.

ArBo
fuente
2

Limpio , 211 207 bytes

import StdEnv,Data.List
z=zipWith
$l=maximum[length k-1\\p<-permutations[(v,[x,y])\\y<-[0..]&u<-l,x<-[0..]&v<-u],(k,[m:n])<-map unzip(subsequences p)|and[all((>)2o sum o map abs)(z(z(-))n[m:n]):z(>)k(tl k)]]

Pruébalo en línea!

Una solución de fuerza bruta que toma una lista de listas de enteros ( [[Int]]).
El controlador TIO toma el mismo formato que los ejemplos a través de STDIN.

Es demasiado lento ejecutar cualquiera de los ejemplos en TIO y probablemente también localmente, pero funciona en teoría.

Éste hace lo mismo más rápido, puede hacer 3x3 o 2x4 en TIO y 4x4 y 3x5 localmente.

Sangrado:

$ l
    = maximum
        [ length k-1
        \\p <- permutations
            [ (v, [x, y])
            \\y <- [0..] & u <- l
            , x <- [0..] & v <- u
            ]
        , (k, [m: n]) <- map unzip
            (subsequences p)
        | and
            [ all
                ((>) 2 o sum o map abs)
                (zipWith (zipWith (-)) n [m:n])
                :
                zipWith (>) k (tl k)
            ]
        ]
Οurous
fuente
2

Python 3 , 219 bytes

e,m=len,enumerate
b=lambda g,x,y:[b(g,i,j)for o in[-1,1]for i,j in[(x+o,y),(x,y+o)]if e(g)>i>=0<=j<e(g[x])and g[x][y]<g[i][j]]
l=lambda t:e(t)and 1+max(map(l,t))
d=lambda g:max(l(b(g,x,y))for x,r in m(g)for y,_ in m(r))

Pruébalo en línea!

La cuadrícula se representa como una lista de listas:

[
    [1, 2, 3, 2, 2],
    [3, 4, 5, 5, 5],
    [3, 4, 6, 7, 4],
    [3, 3, 5, 6, 2],
    [1, 1, 2, 3, 1],
]

Código original sin golf:

def potential_neighbours(x, y):
    return [(x-1, y), (x+1, y), (x, y-1), (x, y+1)]

def neighbours(grid, x, y):
    result = []
    for i, j in potential_neighbours(x, y):
        if 0 <= i < len(grid) and 0 <= j < len(grid[x]) and grid[x][y] < grid[i][j]:
            result += [(i, j)]
    return result

def build_tree(grid, x, y):
    return [build_tree(grid, i, j) for i, j in neighbours(grid, x, y)]

def longest_path_in_tree(tree):
    if len(tree) == 0:
        return 0
    return 1 + max(map(longest_path_in_tree, tree))

def longest_descent(grid):
    trees = [build_tree(grid, x, y) for x, row in enumerate(grid) for y, _ in enumerate(row)]
    return max(map(longest_path_in_tree, trees))
Nishioka
fuente
2

Haskell , 188 186 bytes

-XNoMonomorphismRestriction

f m|c<-[0..length(m!!0)-1],r<-[0..length m-1]=h[g[(x,y)]|x<-r,y<-c,let g((x,y):p)=h[1+g(k:p)|i<-[-1,1],k@(u,v)<-[(x+i,y),(x,y+i)],u#r,v#c,m!!u!!v<m!!x!!y,not$k#p]]
(#)=elem
h=foldl max 0

Pruébalo en línea!

notElem(not.).(#)+4

Pruébalo en línea!

Explicación y Ungolfed

Estrategia: intente recurrentemente todos los caminos posibles, realice un seguimiento de las entradas visitadas y maximice su longitud.

elemnotElem(#)elemmaximize0

safeMaximum = foldl max 0

Ahora estamos listos para definir nuestra función recursiva fun :: [[Integer]] -> Integer:

fun xs
  | c <- [0..length(m!!0)-1]             -- all possible indices of xs' columns
  , r <- [0..length m-1]                 -- all possible indices of xs' rows
  = safeMaximum                          -- maximize ..
      [ g [(x,y)]                        -- .. initially we haven't visited any others
      | x <- c, y<-r                     -- .. all possible entries
-- For the purpose of golfing we define g in the list-comprehension, it takes all visited entries (p) where (x,y) is the most recent
      , let g((x,y):p) = safeMaximum     -- maximize ..
          [ 1 + g(k:p)                   -- .. recurse, adding (x,y) to the visited nodes & increment (the next path will be 1 longer)
          | i <- [-1,1]                  -- offsets [left/up,right/down]
          , k@(u,v) <-[(x+i,y),(x,y+i)]  -- next entry-candidate
          , u#c, v#r                     -- make sure indices are in bound ..
          , m!!u!!v < m!!x!!y            -- .. , the the path is decreasing
          , not$(u,v)#p                  -- .. and we haven't already visited that element
          ]
      ]
ბიმო
fuente
¿Cómo toma esto las cuadrículas? Lista de listas?
Beefster
@Beefster: Sí, dice que [[Integer]]es una lista de listas. Aunque en el TIO vinculado tienes un contenedor parse :: String -> [[Integer]], st. puede usar cadenas divididas en espacios y nuevas líneas.
ბიმო
1

Python 3, 263 227 bytes

def f(m):
 p={(x,y):[c for i in[-1,1]for c in[(x,y+i),(x+i,y)]]for x,y in m};d={c:0 for c in p if not p[c]}
 while len(p)-len(d):
  for c in p:
   for b in p[c]:
    if b in d:d[c]=max(d[b]+1,d.get(c,0))
 return max(d.values())

Pruébalo en línea!

-2 bytes gracias a BMO

Toma cuadrículas en el formato {(0, 0): 1, (1, 0): 2, ...}. Este formato se puede generar a partir del formato de ejemplo utilizando la siguiente función de utilidad:

lambda s,e=enumerate:{(x,y):int(n)for y,l in e(s.split('\n'))for x,n in e(l.split())}
wizzwizz4
fuente