Pers.narod.ru. Алгоритмы. Обход матрицы по раскручивающейся спирали |
Мы хотим получить матрицу следующего вида:
9 8 8 8 8 8 8 8 8 10 9 7 6 6 6 6 6 6 8 10 9 7 5 4 4 4 4 6 8 10 9 7 5 3 2 2 4 6 8 10 9 7 5 3 1 2 4 6 8 10 9 7 5 3 1 2 4 6 8 10 9 7 5 3 3 3 4 6 8 10 9 7 5 5 5 5 5 6 8 10 9 7 7 7 7 7 7 7 8 10 9 9 9 9 9 9 9 9 9 10
(порядок обхода элементов матрицы показан увеличением цифр)
На словах алгоритм очень прост:
1. выбрать начальную точку и направление, шаг step=1;
2. шагнуть на step ячеек в выбранном направлении, повернуть;
3. снова шагнуть на на step ячеек в новом направлении, повернуть, увеличить step на 1;
4. повторить с шага 2.
Код программы-примера на Паскале:
const n=10; {размерность матрицы}
var a:array [1..n,1..n] of integer;
x,y,dx,dy,step,dir,k,s,count,error:integer;
begin
for x:=1 to n do {заполнение матрицы нулями}
for y:=1 to n do a[x,y]:=0;
x:=n div 2; {текущие координаты в матрице - }
y:=n div 2; {начинаем с середины}
step:=1; {сначала шаг будет = 1 элементу}
dir:=1; {первый шаг будет вниз, можно другие направления}
k:=0; {дополнительный счётик поворотов}
count:=0; {счётчик заполненных элементов}
error:=0; {счётчик лишних шагов}
repeat
dx := dir div 10; {смещение по оси x}
dy := dir mod 10; {смещение по оси y}
for s:=1 to step do begin {заполнение матрицы}
if (x>0) and (x<=n) and (y>0) and (y<=n) then begin
a[y,x]:=step;
inc(count);
end
else inc(error); {если можно, ставим элемент, иначе считаем лишний шаг}
inc(x,dx); {изменить текущие координаты в матрице}
inc(y,dy);
end;
if dir=10 then dir:=-1 {10 - вправо}
else if dir=-1 then dir:=-10 {-1 - вверх}
else if dir=-10 then dir:=1 {-10 - влево}
else if dir=1 then dir:=10; {1 - вниз}
inc(k); {считаем, не пора ли повернуть}
if k=2 then begin inc(step); k:=0; end; {поворот каждые 2 шага}
until count=n*n; {надо заполнить всю матрицу}
for x:=1 to n do begin {вывод полученной матрицы}
writeln;
for y:=1 to n do write(a[x,y]:3);
end;
writeln;
writeln ('Illegal steps:',error); {вывели число лишних шагов}
writeln ('Press ENTER to exit');
readln; {ждем нажатия Enter}
end.
Вот что выходит при первом шаге влево от середины матрицы:
9 9 9 9 9 9 9 9 9 10 7 7 7 7 7 7 7 7 8 10 7 5 5 5 5 5 5 6 8 10 7 5 3 3 3 3 4 6 8 10 7 5 3 1 1 2 4 6 8 10 7 5 3 2 2 2 4 6 8 10 7 5 4 4 4 4 4 6 8 10 7 6 6 6 6 6 6 6 8 10 8 8 8 8 8 8 8 8 8 10 10 10 10 10 10 10 10 10 10 10 Illegal steps:10
То есть, мы прошли с девятками вниз слева от первого столбца. Это потому, что стремимся здесь заполнить всю матрицу (см. условие выхода из цикла).
В качестве альтерантивы условие выхода из цикла можно сделать
until step>=n;
или >, а не >=, без использования переменной count.
Тогда некоторые начальные значения dir оставят незаполненные строки или столбцы.
В коде примера заполнение всегда будет по спирали, раскручивающейся против часовой стрелки, подумайте, что изменить, чтобы ходить по часовой? Верно, порядок смены направлений вправо-вверх-влево-вниз нужно поменять на вправо-вниз-влево-вверх, то есть, в коде изменится блок выбора следующего направления:
if dir=10 then dir:=1 else if dir=1 then dir:=-10 else if dir=-10 then dir:=-1 else if dir=-1 then dir:=10;
Также понятно, что если нужно заполнять матрицу последовательно возрастающими значениями, просто напишите
a[y,x]:=count;
вместо step во вложенном цикле for.
Развитие идеи на PHP - здесь.
|
|