Матрица и алгоритм " спираль"
Я хотел спросить, готов ли какой-то алгоритм, который позволил мне это сделать: у меня есть матрица m (col) x n (строка) с m x n элементами. Я хочу дать положение этому элементу, начиная с центра и вращаясь по спирали, например, для матрицы 3x3 у меня есть 9 элементов, определенных так:
5 6 7
4 9 8
3 2 1
или для матрицы una 4 x 3 у меня есть 12 элементов, определите:
8 9 10 1
7 12 11 2
6 5 4 3
или опять же, матрица 5x2 у меня 10 элементов так определена:
3 4
7 8
10 9
6 5
2 1
etc. Я решил в основном определяя массив целого числа из m x n элементов и загружая вручную значение, но в целом мне нравится, что матрица сделана из алгоритма автоматически. Спасибо всем, кто может помочь мне найти что-то такое, Спасибо.
обновление
этот код, делаю точно О я хочу иметь, но не находится в delphi; просто только мне нужно что начать с 1 а не с 0. Для меня важно, что он действителен для любой математики m x n. Кто поможет мне перевести его в Дельфи?
(defun spiral (rows columns)
(do ((N (* rows columns))
(spiral (make-array (list rows columns) :initial-element nil))
(dx 1) (dy 0) (x 0) (y 0)
(i 0 (1+ i)))
((= i N) spiral)
(setf (aref spiral y x) i)
(let ((nx (+ x dx)) (ny (+ y dy)))
(cond
((and (< -1 nx columns)
(< -1 ny rows)
(null (aref spiral ny nx)))
(setf x nx
y ny))
(t (psetf dx (- dy)
dy dx)
(setf x (+ x dx)
y (+ y dy)))))))
> (pprint (spiral 6 6))
#2A ((0 1 2 3 4 5)
(19 20 21 22 23 6)
(18 31 32 33 24 7)
(17 30 35 34 25 8)
(16 29 28 27 26 9)
(15 14 13 12 11 10))
> (pprint (spiral 5 3))
#2A ((0 1 2)
(11 12 3)
(10 13 4)
(9 14 5)
(8 7 6))
еще раз большое спасибо.
4 ответов
на основе классической алгоритм спирали. поддержка неквадратных матриц:
program SpiralMatrix;
{$APPTYPE CONSOLE}
uses
SysUtils;
type
TMatrix = array of array of Integer;
procedure PrintMatrix(const a: TMatrix);
var
i, j: Integer;
begin
for i := 0 to Length(a) - 1 do
begin
for j := 0 to Length(a[0]) - 1 do
Write(Format('%3d', [a[i, j]]));
Writeln;
end;
end;
var
spiral: TMatrix;
i, m, n: Integer;
row, col, dx, dy,
dirChanges, visits, temp: Integer;
begin
m := 3; // columns
n := 3; // rows
SetLength(spiral, n, m);
row := 0;
col := 0;
dx := 1;
dy := 0;
dirChanges := 0;
visits := m;
for i := 0 to n * m - 1 do
begin
spiral[row, col] := i + 1;
Dec(visits);
if visits = 0 then
begin
visits := m * (dirChanges mod 2) + n * ((dirChanges + 1) mod 2) - (dirChanges div 2) - 1;
temp := dx;
dx := -dy;
dy := temp;
Inc(dirChanges);
end;
Inc(col, dx);
Inc(row, dy);
end;
PrintMatrix(spiral);
Readln;
end.
3 x 3:
1 2 3
8 9 4
7 6 5
4 x 3:
1 2 3 4
10 11 12 5
9 8 7 6
2 x 5:
1 2
10 3
9 4
8 5
7 6
там вы идете!!! После 30-ти синтаксических ошибок...
на ideone.com, я бегал с несколько тестов, и кажется, работает хорошо. Я думаю, вы можете увидеть выход там все еще и запустить его самостоятельно...
Я поместил некоторые комментарии в код. Достаточно, чтобы понять. Основную навигационную систему немного сложнее объяснить. Короче говоря, выполнение спирали идет в первом направлении 1 раз, второй 1 раз, третий 2 раза, четвертый 2 раза, пятый 3 раза, 3, 4, 4, 5, 5, и так далее. Я использую то, что я назвал seed
и step
чтобы получить такое поведение.
program test;
var
w, h, m, n, v, d : integer; // Matrix size, then position, then value and direction.
spiral : array of array of integer; // Matrix/spiral itself.
seed, step : integer; // Used to travel the spiral.
begin
readln(h);
readln(w);
setlength(spiral, h, w);
v := w * h; // Value to put in spiral.
m := trunc((h - 1) / 2); // Finding center.
n := trunc((w - 1) / 2);
d := 0; // First direction is right.
seed := 2;
step := 1;
// Travel the spiral.
repeat
// If in the sub-spiral, store value.
if ((m >= 0) and (n >= 0) and (m < h) and (n < w)) then
begin
spiral[m, n] := v;
v := v - 1;
end;
// Move!
case d of
0: n := n + 1;
1: m := m - 1;
2: n := n - 1;
3: m := m + 1;
end;
// Plan trajectory.
step := step - 1;
if step = 0 then
begin
d := (d + 1) mod 4;
seed := seed + 1;
step := trunc(seed / 2);
end;
until v = 0;
// Print the spiral.
for m := 0 to (h - 1) do
begin
for n := 0 to (w - 1) do
begin
write(spiral[m, n], ' ');
end;
writeln();
end;
end.
Если вам действительно нужно, чтобы напечатать текстовые спирали, я позволю вам выровнять цифры. Просто заполните их пробелами.
EDIT:
забыл... Чтобы заставить его работать на ideone, я поставил параметры на 2 строки в качестве входных данных. m, затем n.
например:
5
2
доходность
3 4
7 8
10 9
6 5
2 1
вот прокомментированная реализация JavaScript для того, что вы пытаетесь выполнить.
// return an array representing a matrix of size MxN COLxROW
function spiralMatrix(M, N) {
var result = new Array(M * N);
var counter = M * N;
// start position
var curCol = Math.floor((M - 1) / 2);
var curRow = Math.floor(N / 2);
// set the center
result[(curRow * M) + curCol] = counter--;
// your possible moves RIGHT, UP, LEFT, DOWN * y axis is flipped
var allMoves = [[1,0], [0,-1], [-1,0], [0,1]];
var curMove = 0;
var moves = 1; // how many times to make current Move, 1,1,2,2,3,3,4,4 etc
// spiral
while(true) {
for(var i = 0; i < moves; i++) {
// move in a spiral outward counter clock-wise direction
curCol += allMoves[curMove][0];
curRow += allMoves[curMove][1];
// naively skips locations that are outside of the matrix bounds
if(curCol >= 0 && curCol < M && curRow >= 0 && curRow < N) {
// set the value and decrement the counter
result[(curRow * M) + curCol] = counter--;
// if we reached the end return the result
if(counter == 0) return result;
}
}
// increment the number of times to move if necessary UP->LEFT and DOWN->RIGHT
if(curMove == 1 || curMove == 3) moves++;
// go to the next move in a circular array fashion
curMove = (curMove + 1) % allMoves.length;
}
}
код не самый эффективный, потому что он идет по спирали наивно, не проверяя сначала, действительно ли место, по которому он идет. Он проверяет действительность текущего местоположения только перед тем, как попытаться установить его значение.
хотя на вопрос уже ответили, это альтернативное решение (возможно проще). Решение находится в python (используя numpy для bidimendional массивов), но может быть легко портировано.
основная идея состоит в том, чтобы использовать тот факт, что количество шагов известно (m*n) как конечное условие, и правильно вычислить следующий элемент цикла на каждой итерации:
import numpy as np
def spiral(m, n):
"""Return a spiral numpy array of int with shape (m, n)."""
a = np.empty((m, n), int)
i, i0, i1 = 0, 0, m - 1
j, j0, j1 = 0, 0, n - 1
for k in range(m * n):
a[i, j] = k
if i == i0 and j0 <= j < j1: j += 1
elif j == j1 and i0 <= i < i1: i += 1
elif i == i1 and j0 < j <= j1: j -= 1
elif j == j0 and 1 + i0 < i <= i1: i -= 1
else:
i0 += 1
i1 -= 1
j0 += 1
j1 -= 1
i, j = i0, j0
return a
и вот какие результаты:
>>> spiral(3,3)
array([[0, 1, 2],
[7, 8, 3],
[6, 5, 4]])
>>> spiral(4,4)
array([[ 0, 1, 2, 3],
[11, 12, 13, 4],
[10, 15, 14, 5],
[ 9, 8, 7, 6]])
>>> spiral(5,4)
array([[ 0, 1, 2, 3],
[13, 14, 15, 4],
[12, 19, 16, 5],
[11, 18, 17, 6],
[10, 9, 8, 7]])
>>> spiral(2,5)
array([[0, 1, 2, 3, 4],
[9, 8, 7, 6, 5]])