Haskell , 228 227 225 224 octets
import Data.List
z=zipWith
a!b=div(max(a*a)(a*b))a
l x=z(!)(z(!)x(0:x))$tail x++[0]
s=(\x->length.($x).filter<$>[(>0),(<0)]).nub.(>>=id).(until=<<((==)=<<))((.)>>=id$transpose.map l).z(\i->z(\j x->2^i*j*(2*x-1))[1,3..])[1..]
Essayez-le en ligne!
Explication:
L'idée de cette solution est la suivante: initialiser la matrice avec des valeurs uniques dans chaque cellule, positives pour 1
et négatives pour 0
. Ensuite, comparez à plusieurs reprises chaque cellule avec ses voisins et, si le voisin a le même signe mais un nombre avec une valeur absolue plus grande, remplacez le numéro de la cellule par le numéro du voisin. Une fois que cela atteint un point fixe, comptez le nombre de nombres positifs distincts pour le nombre de 1
régions et les nombres négatifs distincts pour le nombre de 0
régions.
Dans du code:
s=(\x->length.($x).filter<$>[(>0),(<0)]).nub.(>>=id).(until=<<((==)=<<))((.)>>=id$transpose.map l).z(\i->z(\j x->2^i*j*(2*x-1))[1,3..])[1..]
peut être séparé en prétraitement (attribution de numéros aux cellules), itération et post-traitement (comptage des cellules)
Prétraitement
La partie prétraitement est la fonction
z(\i->z(\j x->2^i*j*(2*x-1))[1,3..])[1..]
Qui utilise z
comme abréviation pour zipWith
raser quelques octets. Ce que nous faisons ici est de compresser le tableau bidimensionnel avec des indices entiers sur les lignes et des indices entiers impairs sur les colonnes. Nous faisons cela car nous pouvons construire un entier unique à partir d'une paire d'entiers en (i,j)
utilisant la formule (2^i)*(2j+1)
. Si nous ne générons que des entiers impairs pour j
, nous pouvons ignorer le calcul de 2*j+1
, en économisant trois octets.
Avec le nombre unique, il ne nous reste plus qu'à multiplier dans un signe basé sur la valeur dans la matrice, qui est obtenue comme 2*x-1
Itération
L'itération se fait par
(until=<<((==)=<<))((.)>>=id$transpose.map l)
Étant donné que l'entrée se présente sous la forme d'une liste de listes, nous effectuons la comparaison des voisins sur chaque ligne, transposons la matrice, effectuons à nouveau la comparaison sur chaque ligne (qui, en raison de la transposition, est ce qu'étaient les colonnes auparavant) et transposons à nouveau. Le code qui accomplit l'une de ces étapes est
((.)>>=id$transpose.map l)
où se l
trouve la fonction de comparaison (détaillée ci-dessous) et transpose.map l
effectue la moitié des étapes de comparaison et de transposition. (.)>>=id
exécute son argument deux fois, étant la forme sans point \f -> f.f
et d'un octet plus court dans ce cas en raison des règles de priorité de l'opérateur.
l
est défini dans la ligne ci-dessus comme l x=z(!)(z(!)x(0:x))$tail x++[0]
. Ce code effectue un opérateur de comparaison (!)
(voir ci-dessous) sur chaque cellule avec d'abord son voisin gauche, puis avec son voisin droit, en zippant la liste x
avec la liste décalée à droite 0:x
et la liste décalée à gauche tail x++[0]
tour à tour. Nous utilisons des zéros pour garnir les listes décalées, car elles ne peuvent jamais se produire dans la matrice prétraitée.
a!b
est défini dans la ligne au-dessus de cela comme a!b=div(max(a*a)(a*b))a
. Ce que nous voulons faire ici, c'est la distinction de cas suivante:
- Si
sgn(a) = -sgn(b)
, nous avons deux zones opposées dans la matrice et ne souhaitons pas les unifier, a
reste inchangé
- Si
sgn(b) = 0
, nous avons le cas du coin où b
est le rembourrage et a
reste donc inchangé
- Si
sgn(a) = sgn(b)
, nous souhaitons unifier les deux zones et prendre celle avec la plus grande valeur absolue (pour des raisons de commodité).
Notez que sgn(a)
cela ne peut jamais l'être 0
. Nous accomplissons cela avec la formule donnée. Si les signes de a
et b
diffèrent, a*b
est inférieur ou égal à zéro, tandis que a*a
est toujours supérieur à zéro, nous le sélectionnons donc comme le maximum et divisons avec a
pour revenir a
. Sinon, max(a*a)(a*b)
est abs(a)*max(abs(a),(abs(b))
, et en divisant cela par a
, nous obtenons sgn(a)*max(abs(a),abs(b))
, qui est le nombre avec la plus grande valeur absolue.
Pour itérer la fonction ((.)>>=id$transpose.map l)
jusqu'à ce qu'elle atteigne un point fixe, nous utilisons (until=<<((==)=<<))
, qui est tiré de cette réponse stackoverflow .
Post-traitement
Pour le post-traitement, nous utilisons la partie
(\x->length.($x).filter<$>[(>0),(<0)]).nub.(>>=id)
qui est juste une collection d'étapes.
(>>=id)
écrase la liste des listes en une seule liste,
nub
supprime les doubles,
(\x->length.($x).filter<$>[(>0),(<0)])
partitionne la liste en une paire de listes, une pour les nombres positifs et l'autre pour les nombres négatifs, et calcule leurs longueurs.
[[1,0];[0,1]]
pour vous assurer que la connectivité diagonale n'est pas incluse