Получить диагональные значения спиральной матрицы
у меня есть 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 части: найти числа вдоль диагональной спицы в каждом квадранте. Есть четыре квадранта, поэтому у нас есть четыре спицы:
- Северо-Запад (NW) говорил
- северо-восток (NE) говорил
- Southwest (SW) spoke
- Юго-Восток (SE) говорил
например, в вашей иллюстрации спирали Улама, когда n четное.
- NW говорил У 1, 7,...
- NE говорил У 2, 10,...
- SW говорил у 4, 16,...
- SE говорил у 3, 13,...
проблема подразделяется на два случая:
- N-четное.
- 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
если вам интересно, как я пришел к формулам, есть хорошо установленные результаты для четырех спиц спирали Улама. Вот ссылки:
- https://oeis.org/A054569 (NW говорил в вашей иллюстрации)
- https://oeis.org/A016754 (не говорил в вашей иллюстрации)
- https://oeis.org/A053755 (SW говорил в вашем иллюстрация)
- 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);
?>