Question très cool. Voici une analyse et un algorithme.
L'un des principaux avantages de cet algorithme est qu'il est entièrement réalisé à l'aide de simples calculs de nombres entiers ; il ne comporte pas d'instructions "if" et donc pas de branchements, ce qui signifie que s'il était compilé, il s'exécuterait très rapidement, même pour de très grandes valeurs de n. Cela signifie également qu'il peut être facilement parallélisé pour diviser le travail entre plusieurs processeurs pour très de grandes valeurs de n.
Considérons une grille de 8x8 (ici, l'entrée est techniquement n = 64, mais pour plus de simplicité dans les formules ci-dessous, j'utiliserai n = 8) suivant ce motif en zigzag, comme suit (avec l'axe des lignes et des colonnes indexé sur 0) :
[ 0] [ 1] [ 2] [ 3] [ 4] [ 5] [ 6] [ 7]
[ 0] 1 3 4 10 11 21 22 36
[ 1] 2 5 9 12 20 23 35 37
[ 2] 6 8 13 19 24 34 38 49
[ 3] 7 14 18 25 33 39 48 50
[ 4] 15 17 26 32 40 47 51 58
[ 5] 16 27 31 41 46 52 57 59
[ 6] 28 30 42 45 53 56 60 63
[ 7] 29 43 44 54 55 61 62 64
Remarquez tout d'abord que la diagonale allant de la partie inférieure gauche (0,7) à la partie supérieure droite (7,0) divise la grille en deux composantes quasi-mirromes :
[ 0] [ 1] [ 2] [ 3] [ 4] [ 5] [ 6] [ 7]
[ 0] 1 3 4 10 11 21 22 36
[ 1] 2 5 9 12 20 23 35
[ 2] 6 8 13 19 24 34
[ 3] 7 14 18 25 33
[ 4] 15 17 26 32
[ 5] 16 27 31
[ 6] 28 30
[ 7] 29
et
[ 0] [ 1] [ 2] [ 3] [ 4] [ 5] [ 6] [ 7]
[ 0] 36
[ 1] 35 37
[ 2] 34 38 49
[ 3] 33 39 48 50
[ 4] 32 40 47 51 58
[ 5] 31 41 46 52 57 59
[ 6] 30 42 45 53 56 60 63
[ 7] 29 43 44 54 55 61 62 64
Vous pouvez voir que le bas à droite est juste le haut à gauche reflété et soustrait du carré plus 1 (65 dans ce cas).
Si nous pouvons calculer la partie supérieure gauche, alors la partie inférieure droite peut facilement être calculée en prenant simplement le carré plus 1 ( n * n + 1
) et en soustrayant la valeur aux coordonnées inverses ( value(n - x - 1, n - y - 1)
).
À titre d'exemple, considérons une paire arbitraire de coordonnées dans la partie inférieure droite, disons (6,3), avec une valeur de 48. En suivant cette formule, cela donnerait (8 * 8 + 1) - value(8 - 6 - 1, 8 - 3 - 1)
simplifié à 65 - value(1, 4)
. En regardant la partie supérieure gauche, la valeur à (1,4) est 17. Et 65 - 17 == 48
.
Mais nous devons encore calculer la partie supérieure gauche. Notez que celle-ci peut également être subdivisée en deux composantes qui se chevauchent, une composante dont les chiffres augmentent au fur et à mesure que vous vous dirigez vers le haut et la droite :
[ 0] [ 1] [ 2] [ 3] [ 4] [ 5] [ 6] [ 7]
[ 0] 3 10 21 36
[ 1] 2 9 20 35
[ 2] 8 19 34
[ 3] 7 18 33
[ 4] 17 32
[ 5] 16 31
[ 6] 30
[ 7] 29
Et un composant dont les chiffres augmentent au fur et à mesure que l'on descend vers la gauche :
[ 0] [ 1] [ 2] [ 3] [ 4] [ 5] [ 6] [ 7]
[ 0] 1 4 11 22
[ 1] 5 12 23
[ 2] 6 13 24
[ 3] 14 25
[ 4] 15 26
[ 5] 27
[ 6] 28
[ 7]
Les premiers peuvent également être définis comme les nombres où la somme des coordonnées ( x + y
) est impaire, et les derniers définis comme les nombres où la somme des coordonnées est paire.
Maintenant, l'idée clé ici est que nous dessinons des triangles, donc, sans surprise, le Les nombres triangulaires jouent un rôle de premier plan. La séquence de chiffres du triangle est la suivante : 1, 3, 6, 10, 15, 21, 28, 36, ...
Comme vous pouvez le constater, dans la composante impaire, un nombre triangulaire sur deux commençant par 3 apparaît dans la première ligne (3, 10, 21, 36), et dans la composante paire, un nombre triangulaire sur deux commençant par 1 apparaît dans la première colonne (1, 6, 15, 28).
Plus précisément, pour une paire de coordonnées donnée (x,0) ou (0,y), le numéro du triangle correspondant est triangle(x + 1) ou triangle(y + 1).
Et le reste du graphique peut être calculé en soustrayant progressivement de ces nombres triangulaires vers le haut ou vers le bas des diagonales, ce qui équivaut à soustraire le numéro de ligne ou de colonne donné.
Notez qu'un diagonale peut être défini formellement comme l'ensemble de toutes les cellules ayant une somme donnée de coordonnées. Par exemple, la diagonale avec la somme de coordonnées 3 a pour coordonnées (0,3), (1,2), (2,1) et (3,0). Un seul nombre définit donc chaque diagonale, et ce nombre est également utilisé pour déterminer le nombre de triangles de départ.
Donc, d'après une simple inspection, la formule pour calculer la composante impaire est simplement :
triangle(x + y + 1) - y
Et la formule pour calculer le composant pair est simple :
triangle(x + y + 1) - x
Et la formule bien connue des nombres triangulaires est également simple :
triangle(n) = (n * (n + 1)) / 2
Donc, l'algorithme est :
- Initialise un tableau n x n, où n est la racine carrée de la taille de l'entrée. d'entrée.
- Calculer les indices pour les coordonnées paires de la partie supérieure gauche. Ceci peut être réalisé en imbriquant deux boucles, une boucle externe externe "y allant de 0 à n - 1" et une boucle interne "x allant de y % 2 à y par pas de 2" (en limitant x à l'actuel y, nous ne regardons que la partie supérieure gauche, comme souhaité, et en commençant à y % 2 et en allant par pas de 2, nous n'obtenons que les coordonnées paires). Les indices de boucle peuvent être insérés dans la formule ci-dessus pour obtenir les résultats.
value[x, y] = triangle(x + y + 1) - x
.
- Calculez les indices pour les coordonnées impaires de la partie supérieure gauche. Ceci peut être accompli avec boucles similaires, sauf que la boucle intérieure serait "x allant de y % 2 + 1 à y par pas de 2", pour obtenir uniquement les coordonnées impaires.
value[x, y] = triangle(x + y + 1) - y
.
- Calculez les pour la partie en bas à droite par simple soustraction de
n * n + 1
comme décrit dans la première partie de ce post. Cela peut être fait avec deux boucles imbriquées qui comptent à rebours (et qui délimitent la boucle intérieure sur la boucle extérieure pour n'obtenir que la partie inférieure droite). value[x, y] = (n * n + 1) - value[n - x - 1, n - y - 1]
.
- Aplatissez la grille dans un tableau (en alignant toutes les lignes) et transformez ensuite l'entrée donnée (de taille n * n) en sortie en utilisant les nombres générés dans la grille comme nouveaux indices.