Получить диагональные значения спиральной матрицы

у меня есть n * n спиральная матрица.

Если N = 4

затем матрицы :

 7  8  9 10   
 6  1  2 11  
 5  4  3 12   
16 15 14 13

Если N = 3

 7 8 9
 6 1 2
 5 4 3 

Я хочу получить диагональные значения этой спиральной матрицы.

на n=4 диагональные значения корпуса будут 7,1,3,13,10,2,4,16

Я могу сделать это, сохранив эту матрицу в массиве и пройдя для каждого диагонального значения.
Есть ли лучший способ получить эти значения.

3 ответов


чтобы получить числа на главной диагонали, то можно заметить, что значения

1 = 1
1 + 2 = 3
1 + 2 + 4 = 7
1 + 2 + 4 + 6 = 13

таким образом, общая формула равна 1 + (сумма i = 0 К k из 2*i) для k = 0, 1, 2,... Упрощая это, мы получаем k^2 + k + 1 для k = 0, 1, 2,...

в PHP мы можем генерировать их через что-то вроде этого:

function mainDiagonal($n) {
    $values = array();

    for ($k = 0; $k < $n; $k++) {
        $values[] = $k*$k + $k + 1;
    }

    return $values;
}

чтобы получить числа на антидиагональной для четных N мы видим:

2 = 2
2 + 2 = 4
2 + 2 + 6 = 10
2 + 2 + 6 + 6 = 16

если мы продолжим этот шаблон для больших матриц, мы увидим общее формула

сумма i = 0 К K пола (i / 2)*4 + 2 для k = 0, 1, 2, ...

аналогично для нечетного N мы находим формулу

1 + (сумма i = 0 К k из ceil(i / 2)*4) для k = 0, 1, 2, ...

в PHP мы можем генерировать их через что-то вроде этого:

function antiDiagonal($n) {
    $values = array();

    if ($n % 2 == 0) {
        for ($k = 0; $k < $n; $k++) {
            $accum = 0;

            for ($j = 0; $j <= $k; $j++) {
                $accum += floor($j/2)*4 + 2;
            }

            $values[] = $accum;
        }
    } else {
        for ($k = 0; $k < $n; $k++) {
            $accum = 1;

            for ($j = 0; $j <= $k; $j++) {
                $accum += ceil($j/2)*4;
            }

            $values[] = $accum;
        }
    }

    return $values;
}

обратите внимание, что максимальное значение k меньше размера матрицы.

комбинируя эти функции, получаем:

array_unique(array_merge(mainDiagonal($n), antiDiagonal($n)))

задачу можно разделить на 4 части: найти числа вдоль диагональной спицы в каждом квадранте. Есть четыре квадранта, поэтому у нас есть четыре спицы:

  1. Северо-Запад (NW) говорил
  2. северо-восток (NE) говорил
  3. Southwest (SW) spoke
  4. Юго-Восток (SE) говорил

например, в вашей иллюстрации спирали Улама, когда n четное.

  1. NW говорил У 1, 7,...
  2. NE говорил У 2, 10,...
  3. SW говорил у 4, 16,...
  4. SE говорил у 3, 13,...

проблема подразделяется на два случая:

  1. N-четное.
  2. N нечетно.

Случай 1: N четный

вот формулы для каждой спицы:

NW spoke: f(n) = 4*n*n + 2*n + 1
NE spoke: g(n) = 4*n*n + 4n + 2
SW spoke: h(n) = 4*n*n + 8*n + 4
SE spoke: i(n) = 4*n*n + 6*n + 3

где n = 0, 1, 2, ...

для матрицы 4x4 вычислите следующее set:

{f(0), f(1), g(0), g(1), h(0), h(1), i(0), i(1)}

он дает диагональные значения:

{1, 7, 2, 10, 4, 16, 3, 13}

в общем случае для матрицы NxN, когда n четное, вычислите следующий набор, чтобы получить диагональные значения:

{ f(0), ..., f(N/2 - 1),
  g(0), ..., g(N/2 - 1),
  h(0), ..., h(N/2 - 1),
  i(0), ..., i(N/2 - 1) }

случай 2: n-нечетное

в вашей иллюстрации спирали Улама, когда n нечетно, формулы для каждой спицы:

NW spoke: f(n) = 4*n*n + 2*n + 1
NE spoke: g(n) = 4*n*n + 4*n + 1
SW spoke: h(n) = 4*n*n + 1
SE spoke: i(n) = 4*n*n - 2*n + 1

где n = 0, 1, 2, ...

обратите внимание, что f(0) = g(0) = h(0) = i (0) = 1.

для 3x3 вычислите следующий набор:

{f(0), f(1), g(1), h(1), i(1)}

он дает следующие диагональные значения:

{1, 7, 9, 5, 3}.

в общем случае для матрицы NxN, когда n нечетно, вычислите следующий набор, чтобы получить диагональные значения:

{ f(0), ..., f((N - 1)/2,
  g(0), ..., g((N - 1)/2),
  h(0), ..., h((N - 1)/2),
  i(0), ..., i((N - 1)/2) }

PHP-кода

наконец, вот программа PHP, которая демонстрирует то, что я обсуждал выше.

<?php
function ulam_diag($N)
{
    $result = array();

    if ($N % 2 == 0) {
        for ($n = 0; $n < $N / 2; $n++) {
            $result[] = 4*$n*$n + 2*$n + 1;
            $result[] = 4*$n*$n + 4*$n + 2;
            $result[] = 4*$n*$n + 8*$n + 4;
            $result[] = 4*$n*$n + 6*$n + 3;
        }
    } else {
        $result[] = 1;
        for ($n = 1; $n <= ($N - 1) / 2; $n++) {
            $result[] = 4*$n*$n + 2*$n + 1;
            $result[] = 4*$n*$n + 4*$n + 1;
            $result[] = 4*$n*$n + 1;
            $result[] = 4*$n*$n - 2*$n + 1;         
        }
    }

    sort($result);
    return $result;
}

print_r(ulam_diag(4));
print_r(ulam_diag(3));
?>

выход:

Array
(
    [0] => 1
    [1] => 2
    [2] => 3
    [3] => 4
    [4] => 7
    [5] => 10
    [6] => 13
    [7] => 16
)
Array
(
    [0] => 1
    [1] => 3
    [2] => 5
    [3] => 7
    [4] => 9
)

вот код один Ideone: http://ideone.com/F9jaC0

если вам интересно, как я пришел к формулам, есть хорошо установленные результаты для четырех спиц спирали Улама. Вот ссылки:

  1. https://oeis.org/A054569 (NW говорил в вашей иллюстрации)
  2. https://oeis.org/A016754 (не говорил в вашей иллюстрации)
  3. https://oeis.org/A053755 (SW говорил в вашем иллюстрация)
  4. https://oeis.org/A054554 (SE говорил в вашей иллюстрации)

спирали Улама на ваших иллюстрациях ориентированы иначе, чем популярное представление спиралей Улама, поэтому я взял эти хорошо известные результаты и отрегулировал смещение n для каждой формулы, чтобы она работала с вашей спиралью Улама. Эти корректировки оставлены в качестве упражнений для читателя. ;-)


Ну для каждой строки в матрице у нас есть два диагональных значения. Для получения этих двух значений я использовал две позиции (x1,y1) и (x2,y2) для главной и антидиагоналей.

Ну, я написал этот код:

<?php
    function getSpiralDiagonal($spiralArr,$N){
        $diagonalValueCount = $N*2;
        $xIndexMainDiagonal = 0;
        $yIndexMainDiagonal = 0;
        $xIndexAntiDiagonal = 0;
        $yIndexAntiDiagonal = $N-1;
        while($diagonalValueCount > 0){
            //checking for same position
            if($yIndexMainDiagonal == $yIndexAntiDiagonal){
                echo $spiralArr[$xIndexMainDiagonal][$yIndexMainDiagonal].'<br>';
            }else{
                echo $spiralArr[$xIndexMainDiagonal][$yIndexMainDiagonal].'<br>';
                echo $spiralArr[$xIndexAntiDiagonal][$yIndexAntiDiagonal].'<br>';
            }

            $xIndexMainDiagonal++;
            $yIndexMainDiagonal++;
            $xIndexAntiDiagonal++;
            $yIndexAntiDiagonal--;
            $diagonalValueCount -= 2;
        }
    }

    $spiralArr = array(array('7','8','9'),array('6','1','2'),array('5','4','3'));
    getSpiralDiagonal($spiralArr,3);
?>