Латинскими квадратами называют таблицы, в которых каждая строка и каждый столбец содержат по 1 разу все латинские буквы, начиная с А. Общее количество разных букв определяется размерами квадрата. Например, для квадрата 4 х 4 клетки в каждом столбце и строке будут расположены буквы A, B, C, D.
Важно отметить, что в диагоналях буквы могут и повторяться.
Хотя первоначально таблицы заполнялись латинскими буквами (что и дало название квадрату), гораздо удобнее расставлять в клетках числа от 1 до размерности квадрата.
Теорию построения латинских квадратов разработал великий швейцарский учёный Леонард Эйлер. Сейчас латинские квадраты используют при планировании экспериментов (например, при исследовании урожайности различных сортов злаков), в теории кодирования, в секретной связи. Более «легкомысленное» применение латинских квадратов мы найдём в головоломках - сквэрвордах, футошики, диаго и всем известных судоку.
Но нас интересуют сейчас латинские квадраты не сами по себе, а только как таблицы, заполненные числами, то есть двумерные массивы.
Интерфейс программы нам уже хорошо знаком, поэтому сразу нажмём кнопку с волшебной палочкой, которая всё за нас и решит:
procedure TfrmMain.sbtSolveClick(Sender: TObject);
begin
generate(speNum.Value);
Конечно, никакое чудо не произойдёт, если его заранее не подготовить:
//ГЕНЕРИРОВАТЬ 1 ЛАТИНСКИЙ КВАДРАТ procedure generate(number: integer); var i,j,k,n,x: integer;
B,C,D: array[1..20] of integer;
s: string; time,time0: single;
field: array[0..20,0..20] of integer;
begin
Randomize;
frmMain.lstProtokol.Clear; time0:=GetTickCount(); //засечь начало
for i:= 1 to number do begin B:= i; C:= i; D:= i; end;
n:= number;
//формируем «случайный» столбец: for i:= 1 to number do begin x:= random(n)+1;
B:= C[x]; dec(n);
for k:= x to n do C[k]:= C[k+1];
end;
n:= number;
//формируем «случайную» строку: for i:= 1 to number do begin x:= random(n)+1;
C:= D[x]; dec(n);
for k:= x to n do D[k]:= D[k+1];
end;
//составляем случайный латинский квадрат: for j:= 1 to number do
for i:= 1 to number do begin n:= B[j]+C;
if n > number then n:= n - number; field[j,i]:= n; end;
for j:= 1 to number do begin s: = ’’;
for i := 1 to number do begin
if field[i,j] < 10 then s:= s + ’ ’
else s:= s + ’ ’;
s:= s + inttostr(field[i,j]); end;
frmMain.lstProtokol.Items.Add(s);
end;
time:=(GetTickCount()-time0)/1000; str(time:6:3,s);
frmMain.lstProtokol.Items.Add('');
frmMain.lstProtokol.Items.Add(’Time ’ + s + ’ s’); application.ProcessMessages; end;
Хитроумный алгоритм, по которому генерируется случайный латинский квадрат, мы разбирать не будем, однако заметим, что для его реализации нам потребовались 3 вспомогательных одномерных массива B, C, D:
B,C,D: array[1..20] of integer;
Для самого латинского квадрата мы подготовим двумерный массив:
field: array[1..20,1..20] of integer;
После заполнения и перемешивания массивов B и C в двух циклах for из них составляется латинский квадрат:
for j:= 1 to number do
for i:= 1 to number do begin n:= B[j]+C;
if n > number then n:= n - number; field[j,i]:= n; end;
Ну, а дальше остаётся только вывести результат в окно списка.
Нажимая волшебную кнопку вновь и вновь, вы будете получать каждый раз новый латинский квадрат, который вы легко сможете сохранить на диске.
Программа благодаря хорошему алгоритму генерирует латинские квадраты практически мгновенно, хотя это не так просто - попробуйте сами составить хотя бы маленький квадрат!