Divisez les tableaux et les programmes en deux

10

introduction

Vous avez été chargé d'écrire un programme qui divise un tableau d'entiers rectangulaires en deux de manière égale (pour une raison quelconque). Cette tâche demande beaucoup de calculs, mais heureusement, vous disposez d'une machine à double cœur pour effectuer les calculs. Pour maximiser les avantages du parallélisme, vous décidez de diviser le programme également en deux et de laisser chaque cœur exécuter l'une des parties indépendamment de l'autre.

Entrée et sortie

Votre entrée est un tableau 2D rectangulaire d'entiers non négatifs de taille au moins 1 × 1 , pris dans n'importe quel format raisonnable. Un fractionnement d'un tel tableau est obtenu en divisant chaque ligne horizontale en un préfixe et un suffixe (l'un ou l'autre pouvant être vide). Pour qu'un fractionnement soit valide, deux lignes adjacentes doivent être divisées au même index ou aux index adjacents. Par exemple, considérez le tableau

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

Il s'agit d'un fractionnement valide:

 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

Il s'agit également d'un fractionnement valide:

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

Ce n'est pas un fractionnement valide:

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

Votre sortie doit être la valeur minimale de

abs(sum_of_prefixes - sum_of_suffixes)

sur toutes les séparations valides de l'entrée.

Règles et notation

Vous devez écrire deux programmes (programmes complets ou fonctions) dans la même langue, qui ne doivent pas avoir de code partagé entre eux. Appelons-les P1 et P2 . Le programme P1 prend le tableau d'entrée et sort quelque chose . Le programme P2 prend ce quelque chose en entrée et génère la réponse de la tâche ci-dessus pour le tableau d'entrée.

Votre score est le maximum du nombre d'octets de P1 et P2 , un score plus bas étant meilleur.

Quelques clarifications:

  • Vous pouvez écrire deux prorgams complets, une fonction et un programme complet, ou deux fonctions.
  • Dans le cas de deux programmes complets, la sortie entière de P1 est envoyée à P2 en entrée, comme dans le pipeline Unix P1 | P2. Les programmes doivent fonctionner correctement s'ils sont compilés / interprétés à partir de deux fichiers source distincts.
  • Si l'un ou l'autre programme est une fonction, il est converti en programme complet en ajoutant le code passe-partout nécessaire, et la règle ci-dessus lui est appliquée. En particulier, deux fonctions ne peuvent pas utiliser de fonctions auxiliaires partagées, d'instructions d'importation partagées ou de variables globales partagées.

Cas de test

[[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
la source
Pendant un moment, j'ai pensé que c'était une question multi-threading . J'en attendais plus avec impatience.
Adám

Réponses:

2

Haskell, 102 octets

Fonction 1 (102 octets):

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]

Fonction 2 (90 octets):

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

Plate-forme manquante pour F1 pour en faire un programme complet, y compris le tableau entier codé en dur pour vérifier:

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]]

et pour F2:

main = print . g . read =<< getContents

Vous pouvez maintenant appeler runhaskell f1.hs | runhaskell f2.hsquelles sorties 8.

Comment ça marche: fprend une liste de liste d'entiers.

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

Maintenant, nous avons une liste de toutes les divisions possibles, par exemple la première et une division aléatoire du milieu

[([],[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 fonction gprend une telle liste et

                    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

Remarque: la deuxième fonction peut être jouée un peu plus, mais elle ne change pas le score.

nimi
la source