Este es un desafío en Internet pedido por Palantir Technologies en sus entrevistas .
Un grupo de agricultores tiene algunos datos de elevación, y los ayudaremos a comprender cómo fluye la lluvia sobre sus tierras de cultivo. Representaremos la tierra como un conjunto bidimensional de altitudes y utilizaremos el siguiente modelo, basado en la idea de que el agua fluye cuesta abajo:
Si las cuatro celdas vecinas de una celda tienen altitudes más altas, llamamos a esta celda sumidero; El agua se acumula en los sumideros. De lo contrario, el agua fluirá a la celda vecina con la altitud más baja. Si una celda no es un sumidero, puede suponer que tiene un vecino más bajo único y que este vecino será más bajo que la celda.
Se dice que las células que drenan en el mismo sumidero, directa o indirectamente, son parte de la misma cuenca.
Su desafío es dividir el mapa en cuencas. En particular, dado un mapa de elevaciones, su código debe dividir el mapa en cuencas y generar los tamaños de las cuencas, en orden descendente.
Suponga que los mapas de elevación son cuadrados. La entrada comenzará con una línea con un número entero, S, la altura (y el ancho) del mapa. Las siguientes líneas S contendrán una fila del mapa, cada una con enteros S: las elevaciones de las celdas S en la fila. Algunos agricultores tienen pequeñas parcelas de tierra, como los ejemplos a continuación, mientras que otros tienen parcelas más grandes. Sin embargo, en ningún caso un agricultor tendrá una parcela de tierra mayor que S = 5000.
Su código debe generar una lista separada por espacios de los tamaños de cuenca, en orden descendente. (Los espacios finales se ignoran).
Algunos ejemplos están abajo.
Entrada:
3
1 5 2
2 4 7
3 6 9
Salida:
7 2
Las cuencas, etiquetadas con A y B, son:
A A B
A A B
A A A
Entrada:
1
10
Salida:
1
Solo hay una cuenca en este caso.
Entrada:
5
1 0 2 5 8
2 3 4 7 9
3 5 7 8 9
1 2 5 4 2
3 3 5 2 1
Salida:
11 7 7
Las cuencas, etiquetadas con A, B y C, son:
A A A A A
A A A A A
B B A C C
B B B C C
B B C C C
Entrada:
4
0 2 1 3
2 1 0 4
3 3 3 3
5 5 2 1
Salida:
7 5 4
Las cuencas, etiquetadas con A, B y C, son:
A A B B
A B B B
A B B C
A C C C
fuente
Respuestas:
Mathematica
La lista de tamaños de cuencas puede ser obtenida por
donde
m
están los datos de entrada dados. Para mostrar una matriz como las de la pregunta, se puede reemplazar// Reverse@Sort@Part[Tally[Flatten@#], All, 2] &
con/. {1 -> "A", 2 -> "B", 3 -> "C"} // MatrixForm
o se puede mostrar como una imagen en su lugar utilizando//ImageAdjust//Image
.fuente
JavaScript - 673
707730751e=[],g=[],h=[],m=[],q=[];function r(){a=s,b=t;function d(d,A){n=a+d,p=b+A;c>e[n][p]&&(u=!1,v>e[n][p]&&(v=e[n][p],w=n,k=p))}c=e[a][b],u=!0,v=c,w=a,k=b;0!=a&&d(-1,0);a!=l&&d(1,0);0!=b&&d(0,-1);b!=l&&d(0,1);g[a][b]=w;h[a][b]=k;return u}function x(a,b,d){function c(a,b,c,k){g[a+b][c+k]==a&&h[a+b][c+k]==c&&(d=x(a+b,c+k,d))}d++;0!=a&&c(a,-1,b,0);a!=l&&c(a,1,b,0);0!=b&&c(a,0,b,-1);b!=l&&c(a,0,b,1);return d}y=$EXEC('cat "'+$ARG[0]+'"').split("\n");l=y[0]-1;for(z=-1;z++<l;)e[z]=y[z+1].split(" "),g[z]=[],h[z]=[];for(s=-1;s++<l;)for(t=-1;t++<l;)r()&&m.push([s,t]);for(z=m.length-1;0<=z;--z)s=m[z][0],t=m[z][1],q.push(x(s,t,0));print(q.sort(function(a,b){return b-a}).join(" "));
Resultados de la prueba (usando Nashorn):
Probablemente habría problemas de pila para mapas de tamaño 5000 (pero ese es un detalle de implementación :).
La fuente no minificada en toda su fuguidad:
Obtuve mejores resultados de minimización al dividir los objetos del elemento en matrices separadas, globalizándolos en todas partes posibles y adoptando los efectos secundarios. NSFW.
Los efectos de la minimización del código:
Podría haber logrado cerca de 700 bytes sin editar el código minimizado si hubiera estado dispuesto a modificar la fuente original. Pero no lo hice porque creo que dejarlo como está da una visión interesante desde el punto de partida.
fuente
var e=[],g=[],h=[],l,m=[],q=[]
ae=g=h=l=m=q=[]
. Probablemente también pueda deshacerse de otros usos de lavar
palabra clave si no está sombreando ninguna variable global.Python: 276306
365bytesEste es mi primer intento de golf. Sugerencias son apreciadas!
editar: las importaciones y los archivos de cierre toman demasiados caracteres. Lo mismo ocurre con el almacenamiento de archivos en variables y la comprensión de listas anidadas.
totalmente comentado (2130 bytes ...)
fuente
open('a').read()
, creo.JavaScript (ECMAScript 6) - 226 caracteres
Explicación
Versión anterior - 286 caracteres
Asume que la entrada está en una variable
S
;Explicación
Prueba
Salidas:
[7, 2]
Salidas:
[11, 7, 7]
Salidas:
[5, 7, 4]
fuente
Julia, 315
Solo una función recursiva que determina que la celda actual es un sumidero o encuentra el drenaje, luego lo llama en cada conjunto de índices. No me molesté en hacer la parte de entrada ya que no iba a ganar de todos modos, y esa parte no es divertida.
fuente
Haskell, 271
286Podría haber algún código para jugar golf aquí.
Explicación
Idea básica: para cada celda (i, j) encuentre la celda más baja en el "vecindario". Esto da un gráfico [ (i, j) → (mi, mj) ]. Si una celda es la celda más baja, entonces (i, j) == (mi, mj) .
Este gráfico se puede iterar: para cada a → b en el gráfico, reemplácelo con a → c donde b → c está en el gráfico. Cuando esta iteración no produce más cambios, entonces cada celda del gráfico apunta a la celda más baja a la que fluirá.
Para jugar golf, se han realizado varios cambios: primero, las coordenadas se representan como una lista de longitud 2, en lugar de un par. En segundo lugar, una vez que se han encontrado los vecinos, las celdas se representan por su índice en una matriz lineal de celdas, no en coordenadas 2D. Tercero, como hay n * n celdas, después de n * n iteraciones, el gráfico debe ser estable.
Ungolf'd
fuente
Ruby, 216
Es un enfoque ligeramente diferente, que solo invoca "flujo" en cada cuadro una vez (el rendimiento depende del rendimiento de Array :: index). Va desde la elevación más alta a la más baja, vaciando una celda a la vez en su vecino más bajo y marcando la celda como realizada (agregando 1 a la elevación) cuando se hace.
Comentado y espaciado:
Registro de cambios:
216 - mejor manera de deseleccionar índices fuera de límites
221 - resulta que "11" viene antes de "2" ... vuelve a
to_i
, pero ahorra espacio en nuestrosgets
es.224 - ¿Por qué declarar
s
, de todos modos? Yeach
=>map
229 - golf masivo: clasifique primero las elevaciones
s
(y, por lo tanto, suelte lawhile
cláusula), use enmin_by
lugar desort_by{...}[0]
, no se molesteto_i
por las elevaciones, useflat_map
yselect{}
bloquee271 - movió el tamaño de la cuenca hidrográfica a una nueva matriz y usó sort_by
315: movió los resultados a una matriz que brindaba todo tipo de beneficios y acortó el listado de índice de vecinos. También ganó un char en el índice lambda.
355 - primer compromiso
fuente
Python -
470 447 445 393 392 378 376 375 374369 bytesNo me puedo detener!
No es una solución ganadora, pero me divertí mucho creándola. Esta versión no supone que la entrada se almacene en ningún lugar y, en cambio, la lee desde stdin. Profundidad máxima de recursión = distancia más larga desde un punto hasta su sumidero.
No tengo tiempo para explicarlo hoy, pero aquí está el código sin golf:En realidad es bastante diferente al código original. Leí las líneas S del stdin, dividí, mapeé a ints y aplané las listas para obtener el campo plano. Luego recorro todas las fichas (déjame llamarlas fichas) una vez. La función de flujo comprueba los mosaicos vecinos y elige el que tenga el valor más pequeño. Si es más pequeño que el valor del mosaico actual, muévase a él y repita. Si no, el mosaico actual es un sumidero y se crea una nueva cuenca. El valor de retorno de la recursividad es el id de la cuenca.
fuente
JavaScript (ES6) 190
203Editar Un poco más ES6ish (1 año después ...)
Defina una función con filas de entrada como una cadena, incluidas las nuevas líneas, devuelva la salida como una cadena con espacios en blanco al final
fuente
Perl 6,
419404Nuevas líneas agregadas para mayor claridad. Puede eliminarlos con seguridad.
Vieja solución:
Y, sin embargo, me golpean las soluciones de Python y JavaScript.
fuente