とてもクールな質問です。これが分析とアルゴリズムです。
このアルゴリズムを使用する主な利点は、単純な整数計算を使用してすべてが行われることです。「if」ステートメントがないため、分岐がないため、コンパイルされた場合、n の値が非常に大きい場合でも非常に高速に実行されます。これは、n の値が非常に大きい場合に、複数のプロセッサ間で作業を分割するために簡単に並列化できることも意味します。
8x8 グリッド (ここでは、入力は技術的には n = 64 ですが、以下の式では簡単にするために n = 8 を使用します) を考えてみます。
[ 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
最初に、左下 (0,7) から右上 (7,0) への対角線が、グリッドを 2 つのミラーに近いコンポーネントに分割していることに注意してください。
[ 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
と
[ 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
右下は、左上をミラーリングして、正方形プラス 1 (この場合は 65) から差し引いたものであることがわかります。
左上の部分が計算できれば、右下の部分は、2 乗に 1 を足した値 ( n * n + 1
) と逆座標 ( value(n - x - 1, n - y - 1)
) の値を引くだけで簡単に計算できます。
例として、右下部分の任意の座標のペア、たとえば (6,3) を考えてみましょう。値は 48 です。この式に従うと(8 * 8 + 1) - value(8 - 6 - 1, 8 - 3 - 1)
、65 - value(1, 4)
左上部分を見ると、(1,4) の値は 1765 - 17 == 48
です。
しかし、左上の部分を計算する必要があります。これは、2 つの重複するコンポーネントにさらに細分化することもできます。1 つのコンポーネントは、右に向かうにつれて数字が増加します。
[ 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
そして、左下に向かうにつれて数字が増加する 1 つのコンポーネント:
[ 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]
前者は座標 ( x + y
) の合計が奇数である数として定義することもでき、後者は座標の合計が偶数である数として定義することもできます。
ここでの重要な洞察は、ここで三角形を描いているということです。したがって、驚くことではありませんが、三角形の数がここで重要な役割を果たします。三角形の数列は、1、3、6、10、15、21、28、36、... です。
ご覧のとおり、奇数和コンポーネントでは、3 で始まる 1 つおきの三角数が最初の行 (3、10、21、36) に表示され、偶数和コンポーネントでは、1 で始まる 1 つおきの三角数が表示されます。最初の列 (1、6、15、28)。
具体的には、特定の座標ペア (x,0) または (0,y) に対応する三角形番号は、三角形 (x + 1) または三角形 (y + 1) です。
そして、グラフの残りの部分は、これらの三角形の数から対角線を上または下に徐々に減算することで計算できます。これは、指定された行または列の番号を減算することと同じです。
対角線は、指定された座標の合計を持つすべてのセルのセットとして正式に定義できることに注意してください。たとえば、座標の合計が 3 の対角線の座標は (0,3)、(1,2)、(2,1)、および (3,0) です。したがって、1 つの数値が各対角線を定義し、その数値は開始三角数を決定するためにも使用されます。
したがって、簡単な調査から、奇数和コンポーネントを計算する式は次のようになります。
triangle(x + y + 1) - y
偶数和コンポーネントを計算する式は次のとおりです。
triangle(x + y + 1) - x
また、よく知られている三角形の数の公式も単純です。
triangle(n) = (n * (n + 1)) / 2
したがって、アルゴリズムは次のとおりです。
- nxn 配列を初期化します。ここで、n は入力サイズの平方根です。
- 左上部分の偶数合計座標のインデックスを計算します。これは、外側のループ「y が 0 から n - 1 に進む」と内側のループ「x が y % 2 から y に 2 ずつ進む」という 2 つのループをネストすることで実現できます (現在の y で x を境界付けることにより、必要に応じて左上の部分だけを見て、y % 2 から開始して 2 ずつ進むと、偶数和の座標だけが得られます)。ループ インデックスを上記の式に代入して、結果を得ることができます。
value[x, y] = triangle(x + y + 1) - x
.
- 左上部分の奇数合計座標のインデックスを計算します。これは同様のループで実現できますが、内側のループは「y % 2 + 1 から y まで 2 ずつ進む x」であり、奇数和座標のみを取得します。
value[x, y] = triangle(x + y + 1) - y
.
n * n + 1
この投稿の最初の部分で説明したように、から単純に減算して、右下部分のインデックスを計算します。これは、逆方向にカウントする 2 つのネストされたループで実行できます (そして、内側のループを外側のループにバインドして、右下部分のみを取得します)。value[x, y] = (n * n + 1) - value[n - x - 1, n - y - 1]
.
- グリッドを配列にフラット化し (すべての行を並べる)、グリッドで生成された数値を新しいインデックスとして使用して、指定された入力 (サイズ n * n) を出力に変換します。