Dividir matrices y programas por la mitad

10

Introducción

Se le ha encomendado la tarea de escribir un programa que divida una matriz de enteros rectangular de manera uniforme por la mitad (por cualquier razón). Esta tarea es computacionalmente intensiva, pero afortunadamente tiene una máquina de doble núcleo para realizar los cálculos. Para maximizar los beneficios del paralelismo, decide dividir el programa en partes iguales y dejar que cada núcleo ejecute una de las partes independientemente de la otra.

Entrada y salida

Su entrada es una matriz rectangular 2D de enteros no negativos de tamaño al menos 1 × 1 , tomada en cualquier formato razonable. Una división de dicha matriz se obtiene dividiendo cada fila horizontal en un prefijo y un sufijo (cualquiera de los cuales puede estar vacío). Para que una división sea válida, dos filas adyacentes deben dividirse en el mismo índice o índices adyacentes. Por ejemplo, considere la matriz

2 4 5 5 6 3
9 7 1 7 7 0
0 0 3 6 7 8
1 2 4 7 6 1
6 6 8 2 0 0

Esta es una división válida:

 2;4 5 5 6 3
;9 7 1 7 7 0
;0 0 3 6 7 8
 1;2 4 7 6 1
 6 6;8 2 0 0

Esta también es una división válida:

2 4 5 5 6 3;
9 7 1 7 7;0
0 0 3 6 7;8
1 2 4 7;6 1
6 6 8;2 0 0

Esta no es una división válida:

2 4;5 5 6 3
9 7 1;7 7 0
0;0 3 6 7 8
1 2;4 7 6 1
6 6;8 2 0 0

Su salida será el valor mínimo de

abs(sum_of_prefixes - sum_of_suffixes)

sobre todas las divisiones válidas de la entrada.

Reglas y puntaje

Deberá escribir dos programas (programas completos o funciones) en el mismo idioma, que no debe tener ningún código compartido entre ellos. Llamémoslos P1 y P2 . El programa P1 toma la matriz de entrada y genera algo . El programa P2 toma esto como entrada y genera la respuesta de la tarea anterior para la matriz de entrada.

Su puntaje es el máximo de recuentos de bytes de P1 y P2 , siendo menor el puntaje menor.

Algunas aclaraciones:

  • Puede escribir dos programas completos, una función y un programa completo, o dos funciones.
  • En el caso de dos programas completos, toda la salida de P1 se alimenta a P2 como entrada, como en la tubería de Unix P1 | P2. Los programas deben funcionar correctamente si se compilan / interpretan desde dos archivos fuente separados.
  • Si cualquiera de los programas es una función, se convierte en un programa completo agregando el código repetitivo necesario y se le aplica la regla anterior. En particular, dos funciones no pueden usar funciones auxiliares compartidas, declaraciones de importación compartidas o variables globales compartidas.

Casos de prueba

[[1]] -> 1
[[4,5],[8,3]] -> 4
[[8],[11],[8],[10],[4]] -> 1
[[5,7,0,9,11,2,1]] -> 7
[[146,194,71,49],[233,163,172,21],[121,173,14,302],[259,169,26,5],[164,30,108,37],[88,55,15,2]] -> 3
[[138,2,37,2],[168,382,33,77],[31,199,7,15],[192,113,129,15],[172,88,78,169],[28,6,97,197]] -> 7
[[34,173,9,39,91],[169,23,56,74,5],[40,153,80,60,28],[8,34,102,60,32],[103,88,277,4,2]] -> 0
[[65,124,184,141],[71,235,82,51],[78,1,151,201],[12,24,32,278],[38,13,10,128],[9,174,237,113]] -> 2
[[164,187,17,0,277],[108,96,121,263,211],[166,6,57,49,73],[90,186,26,82,138],[173,60,171,265,96]] -> 8
Zgarb
fuente
Por un momento, pensé que esta era una pregunta multihilo . He estado esperando más de eso.
Adám

Respuestas:

2

Haskell, 102 bytes

Función 1 (102 bytes):

l=length
[]#i=[[]]
(r:s)#i=id=<<[(splitAt j r:)<$>s#j|j<-[i-1..i+1],j>=0,j<l r]
f r=(r#)=<<[0..l$r!!0]

Función 2 (90 bytes):

g::[[([Int],[Int])]]->Int 
g a=minimum$map(\(x,y)->abs$sum(sum<$>x)-sum(sum<$>y))$unzip<$>a

Falta la plantilla para F1 para que sea un programa completo, incluida la matriz de enteros codificados para verificar:

main = print $ f [[164,187,17,0,277],[108,96,121,263,211],[166,6,57,49,73],[90,186,26,82,138],[173,60,171,265,96]]

y para F2:

main = print . g . read =<< getContents

Ahora puede llamar a runhaskell f1.hs | runhaskell f2.hsqué salidas 8.

Cómo funciona: ftoma una lista de la lista de enteros.

f r = (r#)=<<[0..l$r!!0]          -- for each index [0 .. length r] call # with
                                  -- the first parameter being r and
                                  -- collect the results in a single list

[]#i=[[]]                         -- base case. If the list of lists is empty, stop
(r:s)#i                           -- else let r be the first list, s all others
           j<-[i-1..i+1],         -- foreach possible index j for the next line
                 j>=0,j<l r       --    (skipping out of range indices)
     (splitAt j r:)<$>            -- split the current line at j into a pair of
                                  -- lists and prepend it to every element of
                      s#j         -- a recursive call with s and j
id=<<                             -- flatten into a single list

Ahora tenemos una lista de todas las divisiones posibles, por ejemplo, la primera y una aleatoria del medio

[([],[164,187,17,0,277]),                  [([164,187],[17,0,277]),
 ([],[108,96,121,263,211]),                 ([108,96],[121,263,211]),
 ([],[166,6,57,49,73]),                     ([166],[6,57,49,73]),
 ([],[90,186,26,82,138]),                   ([90,186],[26,82,138]),
 ([],[173,60,171,265,96])]                  ([173,60,171],[265,96])]

La función gtoma esa lista y

                    unzip<$>a       -- turn every pair of lists into a list of pairs
  map(\(x,y)->                      -- foreach such pair     
      abs$sum(sum<$>x)-sum(sum<$>y) -- calculate the score
minimum                             -- and find the minimum

Nota: la segunda función se puede jugar un poco más, pero no cambia la puntuación.

nimi
fuente