Программирование на Free Pascal и Lazarus

Обработка матриц в Паскале

Разбить на страницы
Показывать лекцию целиком

Матрица — это двумерный массив, каждый элемент которого имеет два индекса: номер строки и номер столбца.

Объявить двумерный массив (матрицу) можно так:

имя : array [ индекс1_нач.. индекс1_кон, индекс2_нач.. индекс2_кон ]

of тип;

где

  • тип определяет тип элементов массива,
  • имя — имя матрицы,
  • индекс1_нач..индекс1_кон — диапазон изменения номеров строк,
  • индекс2_нач..индекс2_кон — диапазон изменения номеров столбцов матрицы.
  • Например,

    var h : array [ 0.. 1 1, 1.. 10 ] of integer;

    Описана матрица целых чисел h, состоящая из двенадцати строк и десяти столбцов (строки нумеруются от 0 до 11, столбцы от 1 до 10).

    Существует ещё один способ описать матрицы, для этого надо создать новый тип данных:

    type

    новый_тип=array [ индекс1_нач.. индекс1_кон ] of тип;

    var

    имя : array [ индекс2_нач.. индекс2_кон ] of новый_тип;

    или

    type

    новый_тип=array [ список_диапазонов ] of тип;

    var

    имя : новый_тип;

    (рис 6.1) Построчная обработка матрицы (рис 6.2) Алгоритм обработки матрицы по столбцам

    Например:

    type
    massiv=array [ 1.. 30 ] of integer;
    matrica=array [ 0.. 15, 0.. 13 ] of real;
    var
    a, b : array [ 1.. 10 ] of massiv;
    c : matrica;
    

    В данном случае в матрицах a и b есть 10 строк и 30 столбцов, а с — матрица, в которой есть 16 строк и 14 столбцов.

    Для обращения к элементу матрицы необходимо указать её имя и в квадратных скобках через запятую номер строки и номер столбца:

    имя [ номер_строки, номер_столбца ]

    или

    имя [ номер_строки ] [ номер_столбца ]

    Например, h[2,4] Или h[2][4]. — элемент матрицы h, находящийся в строке под номером два и столбце под номером четыре.

    Для обработки всех элементов матрицы необходимо использовать два цикла. Если матрица обрабатывается построчно, то во внешнем цикле последовательно перебираются строки от первой до последней, затем во внутреннем — все (первый, второй, третий и т. д.) элементы текущей строки. При обработке элементов матрицы по столбцам внешний цикл будет перебирать столбцы, внутренний — строки. На рис. 6.1 представлена блок-схема алгоритма обработки матрицы по строкам, на рис. 6.2 — по столбцам. Здесь i — номер строки, j — номер столбца, N — количество строк, M — количество столбцов матрицы A.

    (рис 6.3) Блок-схема ввода элементов матрицы (рис 6.4) Построчный вывод матрицы

    Рассмотрим основные операции, выполняемые над матрицами при решении задач.

    6.1 Ввод-вывод матриц

    Матрицы, как и массивы, нужно вводить (выводить) поэлементно. Вначале следует ввести размеры матрицы, а затем уже в двойном цикле вводить элементы. Блок-схема ввода элементов матрицы изображена на рис. 6.3.

    Вывод можно осуществлять по строкам или по столбцам, но лучше, если элементы располагаются построчно, например,

    2 3 13 35

    5 26 76 37

    52 61 79 17

    Алгоритм построчного вывода элементов матрицы приведён на рис. 6.4.

    Об описании матриц на языке Паскаль было рассказано в разделе 5.2 главы 5, обращение к элементу $$A_{i,j}$$ матрицы можно осуществить c помощью конструкции $$A[i,j]$$ или $$A[i][j]$$.

    Рассмотрим реализацию ввода-вывода матриц в консольных приложениях.

    Для организации построчного ввода матрицы в двойном цикле по строкам и столбцам можно использовать оператор read.

    for i :=1 to N do
    for j :=1 to m do
    read (A[ i, j ] );
    

    В этом случае элементы каждой строки матрицы можно разделять символами пробела или табуляции, и только в конце строки нажимать Enter.

    ЗАДАЧА 6.1. Написать консольное приложение ввода матрицы вещественных чисел и вывода её на экран монитора.

    Ниже приведён пример консольного приложения ввода-вывода матрицы.

    var
    a : array [ 1.. 2 0, 1.. 2 0 ] of real;
    i, j, n,m: integer;
    begin
    {Ввод размеров матрицы}
    writeln ( ’Введите количество строк и столбцов матрицы A ’ );
    readln (N,M);
    {Ввод элементов матрицы.}
    writeln ( ’Введите_матрицу ’ );
    for i :=1 to N do
    for j :=1 to m do
    read (A[ i, j ] );
    {Вывод элементов матрицы.}
    writeln ( ’матрица А  ’ );
    for i :=1 to n do
    begin
    	for j :=1 to m do
    		write ( a [ i, j ] : 8 : 3, ’   ’ ); {Печатается строка.}
    	writeln {Переход на новую строку.}
    end;
    

    На рис. 6.5 представлены результаты работы программы.

    (рис 6.5) Результаты работы программы решения задачи 6.1

    Ввод матрицы также можно организовать с помощью следующего цикла.

    for i :=1 to N do
    for j :=1 to m do
    begin
    write ( ’A( ’, i, ’, ’, j, ’ )= ’ );
    	readln (A[ i, j ] )
    end;
    

    Авторы предлагают читателю самостоятельно разобраться, в чём будет отличие ввода матрицы в этом случае.

    Для ввода-вывода матриц можно использовать компонент типа TStringGrid, с которым мы познакомились в главе 5.

    В качестве примера рассмотрим следующую задачу.

    ЗАДАЧА 6.2. Составить программу транспонирования Транспонированная матрица — матрица, полученная из исходной матрицы $$A(N, M)$$ заменой строк на столбцы. матрицы$$ A$$.

    Блок-схема транспонирования матрицы приведена на рис. 6.6. При транспонировании матрицы $$A(N, M )$$ получается матрица B$$(M, N)$$.

    (рис 6.6) Блок-схема транспонирования матрицы A

    Рассмотрим частный случай транспонирования матрицы фиксированного размера A(4,3).

    На форме разместим метки Label1 и Label2 со свойствами Caption — Заданная матрица $$A$$ и Транспонированная матрица $$B$$, два компонента типа TStringGrid, изменив их свойства так, как показано в табл. 6.1, и кнопку Транспонирование матрицы.

    Окно формы приложения представлено на рис. 6.7.

    Ниже приведён текст подпрограммы с комментариями, которая будет выполняться, если пользователь щёлкнет по кнопке Транспонирование матрицы.

    Свойства компонентов StringGrid1, StringGrid2.
    Свойство StringGrid1 StringGrid2 Описание свойства
    Top 30 30 Расстояние от верхней границы таблицы до верхнего края формы
    Left 15 240 Расстояние от левой границы таблицы до левого края формы
    Height 130 130 Высота таблицы
    Width 200 200 Ширина таблицы
    ColCount 4 5 Количество столбцов
    RowCount 5 4 Количество строк
    DefaultColWidth 30 30 Ширина столбца
    DefaultRowHeight 20 20 Высота строки
    Options.goEditing true false Возможность редактирования таблицы
    (рис 6.7) Форма приложения транспонирования матрицы
    procedure TForm1. Button1Click ( Sender : TObject );
    const n=4;m=3; //Размерность матрицы A(n,m).
    var
    i, j : byte; //Индексы матрицы:
    //i - строки, j - столбцы.
    A: array [ 1.. n, 1..m] of integer; //Исходная матрица.
    B: array [ 1.. m, 1.. n ] of integer; //Транспонированная матрица.
    begin
    //Исходные данные считываются из ячеек таблицы на форме,
    //и их значения записываются в двумерный массив А.
    for i :=1 to n do //Цикл по номерам строк.
    for j :=1 to m do //Цикл по номерам столбцов.
    //Считывание элементов матрицы A из компонента StringGrid1.
    	A[ i, j ] : = StrToInt ( StringGrid1.Cells [ j, i ] );
    //Формирование транспонированной матрицы B, см. блок-схему на
    //рис. 6.6.
    for i :=1 to n do //Цикл по номерам строк.
    for j :=1 to m do //Цикл по номерам столбцов.
    B[ j, i ] : =A[ i, j ];
    //Элементы матрицы B выводятся в ячейки таблицы на форме.
    for i :=1 to n do //Цикл по номерам строк.
    for j :=1 to m do //Цикл по номерам столбцов.
    //Обращение к элементам матрицы происходит по столбцам.
    StringGrid2.Cells [ i, j ] : = IntToStr (B[ j, i ] );
    end;
    

    Результаты работы программы представлены на рис. 6.8.

    (рис 6.8) Результаты работы программы транспонирования матрицы A(3,4)

    Для демонстрации ввода-вывода матриц с помощью компонента типа TStringGrid мы рассмотрели работу с матрицами фиксированного размера A(4,3) и B(3,4). Теперь рассмотрим общий случай решения задачи транспонирования матрицы A(N,M).

    Расположим на форме следующие компоненты:

  • метку label1 с надписью "Введите размерность матрицы";
  • метку label2 с надписью "N=";
  • метку label3 с надписью "M=";
  • метку label4 с надписью "Исходная матрица А";
  • метку label5 с надписью "Преобразованная матрица В";
  • поле ввода Edit1 для ввода числа N;
  • поле ввода Edit2 для ввода числа M;
  • компонент StringGrid1 для ввода исходной матрицы A;
  • компонент StringGrid2 для хранения транспонированной матрицы B;
  • кнопку Button1 с надписью "Ввод" для ввода размеров матрицы А;
  • кнопку Button2 с надписью "Очистить" для очистки содержимого матриц;
  • кнопку Button3 с надписью "Транспонирование" для решения задачи транспонирования матрицы А;
  • кнопку Button4 с надписью "Выход из программы" для завершения работы программы.
  • Можно разместить компоненты на форме так, как показано на рис. 6.9.

    (рис 6.9) Окно формы решения задачи транспонирования матрицы A(N, M ) (рис 6.10) Стартовое окно программы транспонирования матрицы A(N, M )

    Установим свойство видимости (Visible) в False у компонентов метки label4, label5, StringGrid1, StringGrid2, кнопки Button2 и Button3. После этого при запуске программы будут видны только компоненты, отвечающие за ввод размеров матрицы, и кнопка Выход из программы (см. рис. 6.10) Свойству формы Caption присвоено значение Транспонирование матрицы. . Матрицы A и B, их размеры N, M объявим глобально.

    type
    	{ TForm1 }
    {Описание формы}
    	TForm1 = class (TForm)
    		Button1 : TButton;
    		Button2 : TButton;
    		Button3 : TButton;
    		Button4 : TButton;
    		Edit1 : TEdit;
    		Edit2 : TEdit;
    		Label1 : TLabel;
    		Label2 : TLabel;
    		Label3 : TLabel;
    		Label4 : TLabel;
    		Label5 : TLabel;
    		StringGrid1 : TStringGrid;
    		StringGrid2 : TStringGrid;
    	private
    	{private declarations}
    	public
    	{public declarations}
    end;
    var
    {Матрицы A,B}
    	A,B: array [ 1.. 25, 1.. 25 ] of integer;
    {и их размеры}
    	N,M: integer;
    	Form1 : TForm1;
    

    Обработчик кнопки Выход из программы стандартен и представлен ниже.

    procedure TForm1. Button4Click ( Sender : TObject );
    begin
    	Close;
    end;
    

    Теперь напишем обработчик кнопки Ввод, который должен вводить и проверять корректность введения размеров матрицы, устанавливать свойства компонентов StringGrid1 и StringGrid2 (количество строк и столбцов), делать видимым компонент StringGrid1, кнопку Транспонирование, невидимыми компоненты, отвечающие за ввод размеров матрицы (метки label1, label2, label3, поля ввода Edit1 и Edit2, кнопку Ввод ).

    procedure TForm1. Button1Click ( Sender : TObject );
    var i : byte; kod_n, kod_m, kod : integer;
    begin
    //Ввод размерности матрицы.
    //Символьная информация преобразовывается в числовую и
    //записывается в
    	Val ( Edit1. Text,N, kod_m ); //переменную M
    	Val ( Edit2. Text,M, kod_n ); //и переменную N.
    //Если преобразование прошло успешно и введенные размеры
    //удовлетворяют описанию
    //матриц A и B,
    	if ( kod_n=0) and (kod_m=0) and (N>0) and (N<26) and (M>0)
    		and (M<26)
    	then
    //то
    	begin
    //визуализируется первая матрица,
    		StringGrid1. Visible := true;
    		Label4. Visible := true; //соответствующая ей надпись,
    		Button2. Visible := true; //кнопки "Очистить"
    		Button3. Visible := true; //и "Транспонирование".
    		with StringGrid1 do
    		begin
    //Определяем число строк (RowCount) и столбцов(ColCount) в
    //компоненте StringGrid1.
    			ColCount :=M+1;
    			RowCount:=N+1;
    //и нумеруем строки и столбцы матрицы.
    			for i :=1 to RowCount-1 do
    			Cells [ 0, i ] : = IntToStr ( i );
    			for i :=1 to ColCount -1 do
    			Cells [ i, 0 ] : = IntToStr ( i );
    		end;
    StringGrid2. ColCount :=N+1;
    StringGrid2. RowCount:=M+1;
    end
    	else
    	begin
    //При некорректном вводе выдаётся соответствующее сообщение.
    	MessageDlg ( ’Размеры матрицы введены не верно ! ’, MtInformation,
    [mbOk ], 0 );
    //Устанавливаются стартовые параметры в поля ввода.
    	Edit1. Text := ’ 4 ’;
    	Edit2. Text := ’ 3 ’;
    end;
    end;
    

    Теперь напишем обработчик кнопки Транспонирование. При щелчке по этой кнопке становится видимым компонент StrigGrid2, предназначенный для хранения транспонированной матрицы B, соответствующая ему надпись (label5), формируется матрица B. Матрица B выводится в компонент StringGrid2. Кнопка Ввод становится невидимой. Текст обработчика приведён ниже.

    procedure TForm1. Button2Click ( Sender : TObject );
    var i, j : integer;
    begin
    //Визуализируется вторая матрица,
    //соответствующая ей надпись.
    StringGrid2. Visible := true;
    label5. Visible := true;
    for i :=1 to N do //Цикл по номерам строк.
    for j :=1 to M do //Цикл по номерам столбцов.
    //Считывание элементов матрицы A из компонента StringGrid1.
    A[ i, j ] : = StrToInt ( StringGrid1.Cells [ j, i ] );
    with StringGrid2 do
    begin
    for i :=1 to RowCount-1 do //Нумеруются строки
    Cells [ 0, i ] : = IntToStr ( i );
    for i :=1 to ColCount -1 do //и столбцы компонента StringGrid2, в
    Cells [ i, 0 ] : = IntToStr ( i ); //котором отображается матрица B.
    end;
    //Формирование транспонированной матрицы B.
    for i :=1 to N do //Цикл по номерам строк.
    for j :=1 to M do //Цикл по номерам столбцов.
    B[ j, i ] : =A[ i, j ];
    //Элементы матрицы B выводятся в ячейки таблицы на форме.
    for i :=1 to n do //Цикл по номерам строк.
    for j :=1 to m do //Цикл по номерам столбцов.
    //Обращение к элементам матрицы происходит по столбцам.
    StringGrid2.Cells [ i, j ] : = IntToStr (B[ j, i ] );
    Buuton1.Visible := False;
    end;
    

    Осталось написать обработчик события при нажатии на кнопку Очистить. При щелчке по этой кнопке должно происходить следующее:

  • очистка содержимого компонентов StringGrid1, StringGrid2;
  • компоненты StringGrid1, StringGrid2 и соответствующие им метки labe4 и label5, а также кнопки Транспонировать и Очистить становятся невидимыми;
  • становится видимой кнопка Ввод;
  • в поля ввода записываются начальные значения размеров матрицы (N=4, M=3).
  • Текст обработчика кнопки Очистить с комментариями приведен ниже:

    procedure TForm1. Button3Click ( Sender : TObject );
    var i, j : integer;
    begin
    //Очистка компонента StringGrid1.
    	with StringGrid1 do
    		for i :=1 to RowCount-1 do
    		for j :=1 to ColCount -1 do
    			Cells [ j, i ] : = ’ ’;
    //Очистка компонента StringGrid2.
    	with StringGrid2 do
    		for i :=1 to RowCount-1 do
    		for j :=1 to ColCount -1 do
    		Cells [ j, i ] : = ’ ’;
    //Делаем невидимыми компоненты StringGrid1, StringGrid2,
    //labe4, label5.
    	StringGrid1. Visible := False;
    	StringGrid2. Visible := False;
    	label4. Visible := False;
    	label5. Visible := False;
    //Делаем невидимыми кнопки "Транспонировать" и "Очистить".
    	Button2. Visible := False;
    	Button3. Visible := False;
    //Делаем видимой кнопку "Ввод".
    	Button1. Visible :=True;
    //Запись начальных значений размеров матрицы
    //(N=4, M=3).
    	Edit1. Text := ’ 4 ’;
    	Edit2. Text := ’ 3 ’;
    end;
    

    Мы получили работающую программу для транспонирования матрицы. На рис. 6.11 представлены результаты транспонирования матрицы A(2,4).

    Обратите внимание на использование оператора присоединения

    with имя_компонента do оператор;

    который упрощает доступ к свойствам компонента. Внутри оператора With имя компонента для обращения к его свойствам можно не использовать.

    Например, для очистки элементов матрицы A вместо операторов

    for i :=1 to StringGrid1. RowCount-1 do
    	for j :=1 to StringGrid1. ColCount -1 do
    		StringGrid1.Cells [ j, i ] : = ’ ’;
    

    был использован оператор

    with StringGrid1 do
    	for i :=1 to RowCount-1 do
    		for j :=1 to ColCount -1 do
    			Cells [ j, i ] : = ’ ’;
    

    Рассмотрим несколько задач обработки матриц. Для их решения напомним читателю некоторые свойства матриц (рис. 6.12):

    (рис 6.11) Транспонирование матрицы A(2,4) (рис 6.12) Свойства элементов матрицы
  • если номер строки элемента совпадает с номером столбца ($$i = j$$), это означает, что элемент лежит на главной диагонали матрицы;
  • если номер строки превышает номер столбца ($$i > j$$), то элемент находится ниже главной диагонали;
  • если номер столбца больше номера строки ($$i < j$$), то элемент находится выше главной диагонали;
  • элемент лежит на побочной диагонали, если его индексы удовлетворяют равенству $$i + j - 1 = n$$;
  • неравенство $$i + j - 1 < n$$ характерно для элемента, находящегося выше побочной диагонали;
  • соответственно, элементу лежащему ниже побочной диагонали, соответствует выражение $$i + j - 1 > n$$.
  • 6.2 Алгоритмы и программы работы с матрицами

    Рассмотри несколько примеров решения задач обработки матриц.

    ЗАДАЧА 6.3. Найти сумму элементов матрицы, лежащих выше главной диагонали (см. рис. 6.13). (рис 6.13) Рисунок к задаче 6.3

    Рассмотрим два алгоритма решения данной задачи.

    Первый алгоритм решения данной задачи (см. рис. 6.14) построен следующим образом. Вначале переменная S для накапливания суммы обнуляется (S:=0). Затем с помощью двух циклов (первый по строкам, второй по столбцам) перебираются все элементы матрицы, но накапливание суммы происходит только в том случае, если этот элемент находится выше главной диагонали (если выполняется свойство i<j).

    Текст консольного приложения с комментариями приведён ниже.

    var
    a : array [ 1.. 15, 1.. 10 ] of real;
    i, j, n,m: integer; s : real;
    begin
    writeln ( ’введите размеры матрицы ’ );
    writeln ( ’ n - количество строк,  m - количество столбцов ’ );
    readln ( n,m);
    writeln ( ’Введите матрицу A ’ );
    for i :=1 to n do
    for j :=1 to m do
    read ( a [ i, j ] );
    s : = 0;
    for i :=1 to n do
    for j :=1 to m do
    if j>i then {Если элемент лежит выше главной диагонали, то}
    s := s+a [ i, j ]; {наращиваем сумму.}
    writeln ( ’матрица А ’ );
    for i :=1 to n do
    begin
    for j :=1 to m do
    {Здесь важен формат, особенно общая ширина поля!}
    write ( a [ i, j ] : 8 : 3, ’   ’ );
    writeln
    end;
    writeln ( ’сумма элементов  матрицы ’, s : 8 : 3 );
    end.
    
    (рис 6.14) Блок-схема задачи 6.3 (алгоритм 1) (рис 6.15) Блок-схема задачи 6.3 (алгоритм 2)

    Результаты работы программы представлены на рис. 6.16.

    Второй алгоритм решения этой задачи представлен на рис. 6.15.

    В нём проверка условия i<j не выполняется, но, тем не менее, в нём также суммируются элементы матрицы, находящиеся выше главной диагонали. Для пояснения функционирования алгоритма обратимся к рисунку 6.13. В первой строке заданной матрицы необходимо сложить все элементы, начиная со второго. Во второй — все, начиная с третьего, в i–й строке процесс суммирования начнётся с (i+1)-го элемента и так далее. Таким образом, первый цикл работает от 1 до N, а второй от i+1 до M.

    Предлагаем читателю самостоятельно составить программу, соответствующую описанному алгоритму.

    (рис 6.16) Результаты работы программы решения задачи 6.3 ЗАДАЧА 6.4. Вычислить количество положительных элементов квадратной матрицы $$A$$, расположенных по её периметру и на диагоналях. (рис 6.17) Рисунок к условию задачи 6.4

    В квадратной матрице число строк равно числу столбцов. Прежде чем приступить к решению задачи, рассмотрим рисунок 6.17, на котором изображена схема диагоналей квадратных матриц различной размерности.

    Из рисунка видно, что нет необходимости рассматривать все элементы матрицы. Достаточно рассмотреть элементы, расположенные в первой и последней строках, в первом и последнем столбцах, а также на диагоналях квадратной матрицы. Все эти элементы отмечены на рис. 6.17, причём чёрным цветом выделены элементы, которые принадлежат строкам, столбцам и диагоналям. Например, элемент $$A_{1,1}$$ принадлежит первой строке, первому столбцу, и главной диагонали матрицы, элемент $$A_{N,N}$$ находится в последней строке, последнем столбце и принадлежит главной диагонали. Кроме того, если $$N$$ — число нечётное (на рисунке 6.17 эта матрица расположена слева), то существует элемент с индексом (N div 2 + 1, N div 2 + 1), который находится на пересечении главной и побочной диагоналей. При чётном значении $$N$$ (матрица справа на рис. 6.17) диагонали не пересекаются.

    Рассмотрим алгоритм решения задачи. Для обращения к элементам главной диагонали вспомним, что номера строк этих элементов всегда равны номерам столбцов. Поэтому если параметр i изменяется циклически от 1 до N, то $$A_{i,i}$$ — элемент главной диагонали. Воспользовавшись свойством, характерным для элементов побочной диагонали, получим: $$i+j -1 = N \to j = N - i+1$$, следовательно, для строк i=1,2,...,N элемент $$A_{i,N-i+1}$$ — элемент побочной диагонали. Элементы, находящиеся по периметру матрицы записываются следующим образом: $$A_{1,i}$$ — элементы, расположенные в первой строке (i=1,2,...,N), $$A_{N,i}$$ — элементы, расположенные в последней строке (i=1,2,...,N) и, соответственно, $$A_{i,1}$$ — элементы, расположенные в первом столбце (i=1,2,...,N), $$A_{i,N}$$ — в последнем столбце (i=1,2,...,N).

    Алгоритм обработки построим следующим образом: сначала обработаем элементы, расположенные на диагоналях квадратной матрицы. Для этого необходимо в каждой строке (i=1,2,...,N) проверять знак элементов$$ A_{i,i}$$ и $$A_{i,N-i+1}$$.

    for i :=1 to N do
    	begin
    		if ( a [ i, i ] >0) then k:=k+1;
    		if a [ i,N - i +1]>0 then k:=k+1;
    	end;
    

    Так как угловые элементы матрицы уже учтены при проверке диагональных элементов, при обработке элементов, расположенных по периметру матрицы, их учитывать уже не нужно. Поэтому надо перебрать элементы со второго до предпоследнего в первой и последней строке, в первом и последнем столбце.

    for i :=2 to N - 1 do
    	begin
    {Если элемент находится в первой строке.}
    	if ( a [ 1, i ] >0) then k:=k+1;
    {Если элемент находится в последней строке.}
    	if ( a [N, i ] >0) then k:=k+1;
    {Если элемент находится в первом столбце.}
    	if ( a [ i,1] >0) then k:=k+1;
    {Если элемент находится в последнем столбце.}
    	if ( a [ i,N] >0) then k:=k+1;
    end;
    

    Затем нужно проверить, не был ли элемент, находящийся на пересечении диагоналей, подсчитан дважды. Это могло произойти только в том случае, если N — нечётно и элемент, расположенный на пересечении диагоналей На пересечении диагоналей находится элемент с индексами (N div 2 + 1, N div 2 + 1). , положителен.

    if (N mod 2 <> 0) and ( a [ n div 2 + 1, n div 2 + 1 ] > 0) then
    k:=k -1;
    

    Ниже приведён полный текст консольного приложения решения задачи 6.4 с комментариями.

    var a : array [ 1.. 10, 1.. 10 ] of integer;
    	i, j, N, k : integer;
    begin
    	write ( ’N= ’ );
    	readln (N);
    //Ввод исходной матрицы.
    	writeln ( ’Введите матрицу A ’ );
    	for i :=1 to N do
    		for j :=1 to N do
    			read ( a [ i, j ] );
    //Вывод исходной матрицы.
    	writeln ( ’Была введена матрица A: ’ );
    	for i :=1 to N do
    	begin
    		for j :=1 to N do
    			write ( a [ i, j ], ’   ’ );
    		writeln;
    	end;
    	k : = 0;
    //Обработка элементов, расположенных на диагоналях матрицы.
    	for i :=1 to N do
    	begin
    		if ( a [ i, i ] >0) then k:=k+1;
    		if a [ i,N-i +1]>0 then k:=k+1;
    end;
    //Обработка элементов, расположенных по периметру матрицы.
    	for i :=2 to N - 1 do
    	begin
    		if ( a [ 1, i ] >0) then k:=k+1;
    		if ( a [N, i ] >0) then k:=k+1;
    		if ( a [ i,1] >0) then k:=k+1;
    		if ( a [ i,N] >0) then k:=k+1;
    end;
    {Если элемент, находящийся на пересечении диагоналей, подсчитан дважды,}
    {то уменьшить вычисленное значение к на один.}
    	if ( n mod 2<>0) and ( a [N div 2+1,N div 2+1]>0) then
    k:=k _1;
    	writeln ( ’ k= ’, k );
    end.
    

    На рис. 6.18 представлены результаты работы программы решения задачи 6.4.

    (рис 6.18) Результаты решения задачи 6.5 ЗАДАЧА 6.5. Проверить, является ли заданная квадратная матрица единичной.

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

    $$\left(\begin{matrix} 1000\\ 0100\\ 0010\\ 0001 \end{matrix}\right)$$

    Решать задачу будем так. Предположим, что матрица единичная (pr:=true) и попытаемся доказать обратное. В двойном цикле по по строкам (i:=1,2,...,N) и по по столбцам (j:=1,2,...,N) перебираем все элементы матрицы. Если диагональный элемент ($$i = j $$) не равен единице или элемент, расположенный вне диагонали ($$i \not = j$$), не равен нулю Воспользовавшись логическими операциями and и or это сложное условие можно записать так: $$if ((i=j) and (a[i,j]<>1)) or ((i<>j) and (a[i,j]<>0)) then...$$ , то в логическую переменную pr записываем значение false и прекращаем проверку (аварийно покидаем цикл). После цикла проверяем значение pr. Если переменная pr по прежнему равна true, то матрица единичная; в противном случае она таковой не является. Блок-схема алгоритма решения задачи представлена на рис. 6.19.

    (рис 6.19) Блок-схема алгоритма решения задачи 6.5
    program pr_6_5;
    var a : array [ 1.. 10, 1.. 10 ] of real;
    	i, j, n : integer;
    	pr : boolean;
    begin
    	writeln ( ’Введите размер матрицы ’ );
    	readln ( n );
    	writeln ( ’Введите матрицу ’ );
    	for i :=1 to n do
    		for j :=1 to n do
    		read ( a [ i, j ] );
    {Предположим, что матрица единичная,}
    {и присвоим логической переменной значение "истина".}
    {Если значение этой переменной при выходе из цикла не изменится, это}
    {будет означать, что матрица действительно единичная.}
    	pr := true;
    	for i :=1 to n do
    		for j :=1 to n do
    		if ( ( i=j ) and ( a [ i, j ]<>1)) or ( ( i <>j ) and ( a [ i, j ]<>0))
    		  then
    {Если элемент лежит на главной диагонали и не равен единице или элемент}
    {лежит вне главной диагонали и не равен нулю, то}
    begin
    {логической переменной присвоить значение "ложь"}
    {это будет означать, что матрица единичной не является,}
    pr := false;
    {выйти из цикла.}
    break;
    end;
    {Проверка значения логической переменной и печать результата.}
    if pr then
    writeln ( ’Матрица единичная ’ )
    else writeln ( ’Матрица не является единичной ’ );
    end.
    
    ЗАДАЧА 6.6. Преобразовать исходную матрицу так, чтобы последний элемент каждого столбца был заменён разностью минимального и максимального элемента в этом же столбце.

    Для решения данной задачи необходимо найти в каждом столбце максимальный и минимальный элементы, после чего в последний элемент столбца записать их разность. Блок-схема алгоритма решения приведена на рис. 6.20.

    Ниже приведён текст консольного приложения с комментариями.

    program pr_6_6;
    	var a : array [ 1.. 25, 1.. 25 ] of real;
    	i, j, n,m: integer;
    	max, min : real;
    	begin
    {Ввод размеров матрицы.}
    	writeln ( ’Введите размеры матрицы ’ );
    	readln ( n,m);
    {Ввод исходной матрицы.}
    	writeln ( ’Введите матрицу ’ );
    	for i :=1 to n do
    		for j :=1 to m do
    			read ( a [ i, j ] );
    {Последовательно перебираем все столбцы матрицы.}
    	for j :=1 to m do
    	begin
    {Максимальным и минимальным объявляем первый элемент текущего (j-го)}
    {столбца матрицы.}
    	max:=a [ 1, j ];
    	min:=a [ 1, j ];
    {Последовательно перебираем все элементы в текущем (j-м) столбце}
    {матрицы.}
    	for i :=2 to n do
    	begin
    {Если текущий элемент больше максимального, то его и объявляем}
    {максимальным.}
    		if a [ i, j ]>max then max:=a [ i, j ];
    {Если текущий элемент меньше минимального, то его и объявляем}
    {минимальным.}
    		if a [ i, j ]<min then min:=a [ i, j ];
    	end;
    {В последний элемент столбца записываем разность между максимальным и}
    {минимальным элементами столбца.}
    		a [ n, j ] : =max _min;
    	end;
    {Вывод преобразованной матрицы.}
    	writeln ( ’Преобразованная матрица ’ );
    	for i :=1 to n do
    		begin
    			for j :=1 to m do
    				write ( a [ i, j ] : 7 : 3, ’   ’ );
    		writeln;
    	end;
    end.
    
    (рис 6.20) Блок-схема алгоритма решения задачи 6.6

    Теперь давайте создадим визуальное приложение, реализующее рассмотренный алгоритм. За основу возьмём форму (см. рис. 6.9) и проект транспонирования матрицы A(N,M), разработанные для задачи 6.2. Окно формы несколько изменим (рис. 6.9). Кнопку Транспонирование переименуем в Преобразование матрицы, а свойством Caption метки label5 установим Преобразованная матрица A. Кроме того, изменим свойство Caption формы (см. рис. 6.21). Окно изменённой формы представлено на рис. 6.21.

    Обработчики кнопок Ввод, Очистить, Выход из программы изменятся мало. Рассмотрим алгоритм работы обработчика кнопки Преобразование матрицы. В этом обработчике будет производиться считывание матрицы из компонента StringGrid1, преобразование матрицы A по алгоритму, представленному на рис. 6.20, вывод преобразованной матрицы в компонент StringGrid2.

    (рис 6.21) Окно формы решения задачи 6.6

    Текст модуля визуального приложения решения задачи 6.6 с комментариями приведён ниже.

    unit Unit1;
    {$mode objfpc}{$H+}
    interface
    uses
    	Classes, SysUtils, LResources, Forms, Controls, Graphics,
    	Dialogs, StdCtrls, Grids;
    //Описание формы
    type
    	{ TForm1 }
    	TForm1 = class (TForm)
    	Button1 : TButton;
    	Button2 : TButton;
    	Button3 : TButton;
    	Button4 : TButton;
    	Edit1 : TEdit;
    	Edit2 : TEdit;
    	Label1 : TLabel;
    	Label2 : TLabel;
    	Label3 : TLabel;
    	Label4 : TLabel;
    	Label5 : TLabel;
    	StringGrid1 : TStringGrid;
    	StringGrid2 : TStringGrid;
    	procedure Button1Click ( Sender : TObject );
    	procedure Button2Click ( Sender : TObject );
    	procedure Button3Click ( Sender : TObject );
    	procedure Button4Click ( Sender : TObject );
    private
    	{private declarations}
    public
    	{public declarations}
    	end;
    var
    	A: array [ 1.. 2 5, 1.. 2 5 ] of real;
    	N,M: integer;
    	Form1 : TForm1;
    implementation
    { TForm1 }
    //Обработчик кнопки "Выход из программы".
    procedure TForm1. Button4Click ( Sender : TObject );
    begin
    	Close;
    end;
    //Обработчик первой кнопки — кнопки ввода размерности матрицы.
    procedure TForm1. Button1Click ( Sender : TObject );
    var i : byte; kod_n, kod_m, kod : integer;
    begin
    //Ввод размерности матрицы.
    //Символьная информация преобразовывается в числовую и
    //записывается в переменные N и M.
    	Val ( Edit1. Text,N, kod_m );
    	Val ( Edit2. Text,M, kod_n );
    	//Если преобразование прошло успешно и введенные размеры
    //удовлетворяют описанию матриц A и B,
    	if ( kod_n=0) and (kod_m=0) and (N>0) and (N<26) and (M>0)
    		and (M<26)
    then
    //то
    	begin
    //визуализируется первая матрица,
    	StringGrid1. Visible := true;
    //соответствующая ей надпись,
    	Label4. Visible := true;
    //кнопки "Очистить"
    	Button2. Visible := true;
    //и "Транспонирование"
    	Button3. Visible := true;
    	with StringGrid1 do
    		begin
    			ColCount :=M+1;
    			RowCount:=N+1;
    //и нумеруются строки и
    			for i :=1 to RowCount-1 do
    				Cells [ 0, i ] : = IntToStr ( i );
    //столбцы первой таблицы.
    			for i :=1 to ColCount -1 do
    				Cells [ i, 0 ] : = IntToStr ( i );
    		end;
    		StringGrid2. ColCount :=M+1;
    		StringGrid2. RowCount:=N+1;
    	end
    	else
    	begin
    //При некорректном вводе выдается соответствующее сообщение.
    		MessageDlg ( ’Размеры матрицы введены неверно! ’,
    		MtInformation, [ mbOk ], 0 );
    //Устанавливаются стартовые параметры в поля ввода.
    		Edit1. Text := ’ 4 ’;
    		Edit2. Text := ’ 3 ’;
    	end;
    end;
    //Обработчик кнопки "Преобразование матрицы".
    procedure TForm1. Button2Click ( Sender : TObject );
    var i, j : integer;
    	max, min : real;
    begin
    	StringGrid2. Visible := true;
    	label5. Visible := true;
    	for i :=1 to N do //Цикл по номерам строк.
    		for j :=1 to M do //Цикл по номерам столбцов.
    //Считывание элементов матрицы A из компонента StringGrid1,
    			A[ i, j ] : = StrToFloat ( StringGrid1.Cells [ j, i ] );
    			with StringGrid2 do
    			begin
    				for i :=1 to RowCount-1 do //и нумеруются
    					Cells [ 0, i ] : = IntToStr ( i ); //строки и
    				for i :=1 to ColCount -1 do //столбцы второй матрицы.
    					Cells [ i, 0 ] : = IntToStr ( i );
    			end;
    //Решение задачи 6.6.
    	for j :=1 to m do
    	begin
    {Максимальным и минимальным объявляем первый элемент текущего (j-го)}
    {столбца матрицы.}
    	max:=a [ 1, j ];
    	min:=a [ 1, j ];
    {Последовательно перебираем все элементы в текущем (j-м) столбце}
    {матрицы.}
    		for i :=2 to n do
    		begin
    {Если текущий элемент больше максимального, то его и объявляем}
    {максимальным.}
    			if a [ i, j ]>max then max:=a [ i, j ];
    {Если текущий элемент меньше минимального, то его и объявляем}
    {минимальным.}
    			if a [ i, j ]<min then min:=a [ i, j ];
    		end;
    {В последний элемент столбца записываем разность между максимальным и}
    {минимальным элементами столбца.}
    	a [ n, j ] : =max _min;
    	end;
    //Элементы преобразованной матрицы A выводятся в ячейки
    //таблицы на форме.
    	for i :=1 to N do //Цикл по номерам строк.
    		for j :=1 to M do //Цикл по номерам столбцов.
    //Запись элемента преобразованной матрицы A в ячейку StringGrid2.
    		StringGrid2.Cells [ j, i ] : = FloatToStr (A[ i, j ] );
    //Делаем первую кнопку невидимой.
    	Button1. Visible := False;
    end;
    //Обработчик кнопки "Очистить"
    procedure TForm1. Button3Click ( Sender : TObject );
    	var i, j : integer;
    begin
    //Очистка компонента StringGrid1.
    	with StringGrid1 do
    	for i :=1 to RowCount-1 do
    		for j :=1 to ColCount -1 do
    			Cells [ j, i ] : = ’ ’;
    //Очистка компонента StringGrid2.
    	with StringGrid2 do
    		for i :=1 to RowCount-1 do
    			for j :=1 to ColCount -1 do
    				Cells [ j, i ] : = ’ ’;
    //Делаем невидимыми компоненты StringGrid1, StringGrid2,
    //labe4, label5.
    	StringGrid1. Visible := False;
    	StringGrid2. Visible := False;
    	label4.Visible := False;
    	label5.Visible := False;
    //Делаем невидимыми кнопки "Транспонировать" и "Очистить".
    	Button2. Visible := False;
    	Button3. Visible := False;
    //Делаем видимой кнопку "Ввод".
    	Button1. Visible :=True;
    //Запись начальных значений размеров матрицы (N=4,
    //M=3).
    	Edit1. Text := ’ 4 ’;
    	Edit2. Text := ’ 3 ’;
    end;
    initialization
    	{$I unit1.lrs}
    end.
    

    На рис. 6.22 представлено окно с результатами решения задачи.

    ЗАДАЧА 6.7. Поменять местами $$n$$-й и $$r$$-й столбцы матрицы $$A(K, M )$$.

    Задача сводится к обмену $$n$$-го и $$r$$-го элемента во всех строках матрицы.

    Блок-схема приведена на рис. 6.23.

    Ниже приведён листинг консольного приложения с комментариями.

    type matrica=array [ 1.. 15, 1.. 15 ] of real;
    var
    a : matrica;
    i, j, k,m, n, r : byte; b : real;
    begin
    //Ввод размеров матрицы.
    write ( ’ k= ’ ); readln ( k );
    write ( ’m= ’ ); readln (m);
    //Ввод матрицы A.
    writeln ( ’Матрица A ’ );
    for i :=1 to k do
    for j :=1 to m do
    read ( a [ i, j ] );
    //Ввод номеров столбцов матрицы, подлежащих обмену.
    repeat
    write ( ’ n= ’ );
    readln ( n );
    write ( ’ r= ’ );
    readln ( r );
    {Ввод считается верным, если n и r не больше m и не равны друг другу.}
    until ( n<=m) and ( r<=m) and ( n<>r );
    {Элементы столбца с номером r заменить элементами столбца с номером n.}
    for i :=1 to k do
    begin
    b:=a [ i, n ];
    a [ i, n ] : = a [ i, r ];
    a [ i, r ] : = b
    end;
    writeln ( ’Преобразованная матрица A ’ );
    for i :=1 to k do
    begin
    for j :=1 to m do
    write ( a [ i, j ] : 7 : 3, ’   ’ );
    writeln;
    end;
    end.
    
    (рис 6.22) Результаты решения задачи 6.6 (рис 6.23) Блок-схема алгоритма решения задачи 6.7

    Результаты работы программы приведены на рис. 6.24.

    (рис 6.24) Результаты решения задачи 6.7
    ЗАДАЧА 6.8. Преобразовать матрицу $$A(m, n)$$ так, чтобы строки с нечётными индексами были упорядочены по убыванию, c чётными — по возрастанию.

    Каждая строка матрицы является одномерным массивом. Поэтому для упорядочения строки или столбца можно использовать обычные алгоритмы сортировки массивов. При решении задачи необходимо последовательно просматривать все строки матрицы, если номер строки нечётный, то сортируем строку методом пузырька по убыванию, иначе — по возрастанию. Блок-схема этого алгоритма представлена на рис. 6.25.

    (рис 6.25) Блок-схема алгоритма решения задачи 6.8

    Ниже представлено консольное предложение для решения этой задачи с комментариями.

    var a : array [ 1.. 15, 1.. 15 ] of real;
    	j, i, k,m, n : byte; b : real;
    begin
    //Ввод размеров матрицы.
    	writeln ( ’введите m и n ’ );
    readln (m, n );
    //Ввод матрицы.
    writeln ( ’Матрица А ’ );
    for i :=1 to m do
    for j :=1 to n do
    read ( a [ i, j ] );
    //Преобразование матрицы.
    for i :=1 to m do
    if ( i mod 2)=0 then {Если номер строки четный, то}
    begin {упорядочить ее элементы по возрастанию.}
    {Упорядочение строки матрицы методом пузырька по возрастанию.}
    for k:=1 to n-1 do
    for j :=1 to n-k do
    if a [ i, j ] > a [ i, j +1] then
    begin
    b:=a [ i, j ];
    a [ i, j ] : = a [ i, j + 1 ];
    a [ i, j +1]:=b;
    end
    end
    else {Если номер строки нечетный, то упорядочить ее элементы по}
    {убыванию.}
    {Упорядочение строки матрицы методом пузырька по убыванию.}
    for k:=1 to n-1 do
    for j :=1 to n-k do
    if a [ i, j ] < a [ i, j +1] then
    begin
    b:=a [ i, j ];
    a [ i, j ] : = a [ i, j + 1 ];
    a [ i, j +1]:=b;
    end;
    //Вывод преобразованной матрицы.
    writeln ( ’преобразованная матрица A ’ );
    for i :=1 to m do
    begin
    for j :=1 to n do
    write ( a [ i, j ] : 7 : 3, ’   ’ );
    writeln
    end
    end.
    

    На рис. 6.26 приведены результаты работы программы.

    (рис 6.26) Результаты решения задачи 6.8 ЗАДАЧА 6.9. Задана матрица целых положительных чисел $$A(n, m)$$. Сформировать вектор $$P (n)$$, в который записать сумму простых чисел каждой строки матрицы в четверичной системе счисления; если в строке нет простых чисел, в соответствующий элемент массива записать число 0.

    Для решения этой задачи нам понадобятся функции проверки, является ли число простым, и перевода целого числа в четверичную систему счисления. Алгоритм проверки, является ли число простым, уже неоднократно рассматривался в книге. Функция этой проверки подробно рассматривалась в главе 5 при решении задачи 5.7. Поэтому здесь просто приведем её текст.

    function prostoe (N: integer ) : boolean;
    var i : integer;
    	pr : boolean;
    begin
    if N<1 then pr := false
    else
    begin
    	pr := true;
    	for i :=2 to N div 2 do
    		if (N mod i = 0) then
    		begin
    			pr := false;
    			break;
    	end;
    end;
    prostoe:= pr;
    end;
    

    В этой же главе 5 мы рассматривали алгоритм (рис. 5.42) и функцию перевода (function perevod(N:real;P:word;kvo:word):real;) вещественного числа в $$p$$-чную систему счисления (задача 5.10). Нужная нам функция перевода целого числа в четверичную систему счисления является частным случаем рассмотренной ранее функции perevod. Ниже приведён текст функции perevod4, которая переводит целое положительное число в четверичную систему счисления.

    {Функция перевода целого числа N в четверичную систему счисления.}
    function perevod4 (N: word ) : word;
    	var s1, i, q, ost : word;
    begin
    {В переменной s1 мы будем собирать число в четверичной системе}
    {счисления.}
    	s1 : = 0;
    {В переменной q будем последовательно хранить степени десяти; вначале}
    {туда записываем 1 - десять в 0 степени, а затем в цикле будем}
    {последовательно умножать q на 10.}
    q : = 1;
    {Перевод целого числа, пока число не станет равным 0.}
    	while (N<>0) do
    	begin
    {Вычисляем ost - очередной разряд числа, как остаток от деления N на 4}
    {(основание системы счисления).}
    	ost :=N mod 4;
    {Очередной разряд числа умножаем на 10 в степени i и добавляем к}
    {формируемому числу s1.}
    	s1 := s1+ost * q;
    {Уменьшаем число N в 4 раза путем целочисленного деления на 4.}
    	N1:=N1 div 4;
    {Формируем следующую степень десятки.}
    	q:=q * 10;
    end;
    //Возвращаем число в четверичной системе счисления.
    	perevod := s1;
    end;
    

    В каждой строке надо найти сумму простых чисел, а затем полученное число перевести в четверичную систему счисления. Поэтому необходимо для каждой строки (i:=1,2,..,n) выполнить следующее: обнулить сумму S (S:=0), организовать цикл по элементам строки (j:=1,2,...,m), внутри которого проверять, является ли текущий элемент Ai,j простым, и если является, добавлять его к сумме S. После выхода из цикла по j необходимо проверить, были ли в строке с номером i простые числа (S>0), и если были, перевести S в четверичную систему счисления и сформировать соответствующий элемент массива P (P[i]:=perevod4(S)).

    (рис 6.27) Блок-схема алгоритма решения задачи 6.9

    Блок-схема алгоритма приведена на рис. 6.27.

    Полный текст консольного приложения приведён ниже.

    program pr_6_9;
    function prostoe (N: integer ) : boolean;
    var i : integer;
    	pr : boolean;
    begin
    if N<1 then pr := false
    else
    begin
    	pr := true;
    	for i :=2 to N div 2 do
    		if (N mod i = 0) then
    		begin
    			pr := false;
    			break;
    		end;
    end;
    prostoe := pr;
    end;
    function perevod4 (N: word ) : word;
    	var s1, q, ost : word;
    begin
    {В переменной s1 мы будем собирать число в четверичной системе}
    {счисления.}
    	s1 : = 0;
    {В переменной q будем последовательно хранить степени десяти, вначале}
    {туда записываем 1 - десять в 0 степени, а затем в цикле будем}
    {последовательно умножать q на 10.}
    q : = 1;
    {Перевод целого числа, пока число не станет равным 0.}
    		while (N<>0) do
    		begin
    {Вычисляем ost - очередной разряд числа, как остаток от деления N на 4}
    {(основание системы счисления).}
    		ost :=N mod 4;
    {Очередной разряд числа умножаем на 10 в степени i и добавляем к}
    {формируемому числу s1.}
    		s1 := s1+ost * q;
    {Уменьшаем число N в 4 раза путем целочисленного деления на 4.}
    		N:=N div 4;
    {Формируем следующую степень десятки.}
    		q:=q * 1 0;
    	end;
    //Возвращаем число в четверичной системе счисления.
    	perevod4 := s1;
    end;
    var S, i, j, n,m: word;
    	a : array [ 1.. 2 5, 1.. 2 5 ] of word;
    	p : array [ 1.. 2 5 ] of word;
    begin
    //Ввод размеров матрицы.
    	writeln ( ’Введите размеры матрицы ’ );
    	readln ( n,m);
    //Ввод матрицы.
    	writeln ( ’Введите матрицу A ’ );
    	for i :=1 to n do
    		for j :=1 to m do
    			read (A[ i, j ] );
    {Последовательно перебираем все строки матрицы для формирования суммы}
    {простых чисел каждой строки.}
    	for i :=1 to n do
    	begin
    //Вначале сумма равна нулю.
    		S : = 0;
    //Перебираем все элементы в i-й строке матрицы.
    		for j :=1 to m do
    //Если очередной элемент в i-й строке матрицы - простое число,
    //то добавляем его к сумме.
    			if prostoe (A[ i, j ] ) then s := s+A[ i, j ];
    {Если в строке были простые числа, то их сумму переводим в четверичную}
    {систему счисления и записываем в p[i].}
    			if s >0 then p [ i ] : = perevod4 ( s )
    {Если в строке не было простых чисел, то p[i]:=0.}
    		else p [ i ] : = 0;
    	end;
    //Вывод сформированного массива P.
    	writeln ( ’Массив P ’ );
    	for i :=1 to n do
    		write (P [ i ], ’   ’ );
    	writeln;
    end.
    

    Результаты работы программы представлены на рис. 6.28.

    (рис 6.28) Результаты работы программы решения задачи 6.9
    ЗАДАЧА 6.10. Написать программу умножения двух матриц: $$A(N, M )$$ и $$B(M, L)$$.

    Напомним некоторые сведения из курса математики. Умножать можно только матрицы, у которых количество столбцов в первой матрице совпадает с количеством строк во второй матрице. Матрица-произведение имеет столько строк, сколько было в первой матрице и столько столбцов, сколько было во второй. Таким образом, при умножении матрицы A(N,M) на матрицу B(M,L) получается матрица C(N,L). Каждый элемент матрицы C[i,j] является скалярным произведением i-й строки матрицы A и j-го столбца матрицы B. В общем виде формула для нахождения элемента $$c_{i,j}$$ матрицы имеет вид:

    (рис 6.29) Блок-схема умножения двух матриц $$c_{i,j}=\sum\limits_{k=1}^{M}a_{ik}b_{kj},$$

    где $$i = 1,..., N$$ и $$j = 1,..., L$$.

    Рассмотрим более подробно формирование матрицы C(3,2) как произведения матриц A(3,3) и B(3,2).

    $$\left(\begin{matrix} c_{11}c_{12}\\ c_{21}c_{22}\\ c_{31}c_{32}\end{matrix}\right)= \left(\begin{matrix} a_{11}b_{11}+a_{12}b_{21}+a_{13}b_{31} a_{11}b_{12}+a_{12}b_{22}+a_{13} b_{32}\\ a_{21}b_{11}+a_{22}b_{21}+a_{23}b_{31} a_{21}b_{12}+a_{22}b_{22}+a_{23}b_{32}\\ a_{31}b_{11}+a_{32}b_{21}+a_{33}b_{31} a_{31}b_{12}+a_{32}b_{22}+a_{33}b_{32} \end{matrix}\right).$$

    Следует помнить, что $$A \cdot B \not = B \cdot A$$.

    Блок-схема, реализующая умножение каждого элемента матрицы C по формуле (6.1), приведена на рис. 6.29.

    Ниже приведён текст программы умножения двух матриц с комментариями.

    type
    	matrica=array [ 1.. 15, 1.. 15 ] of real;
    var
    	a, b, c : matrica;
    	i, j,M,N, L, k : byte;
    begin
    	//Ввод размеров матриц.
    	writeln ( ’введите n,m и  l ’ );
    	readln (N, M, L );
    //Ввод матрицы A.
    	writeln ( ’Матрица A ’ );
    	for i :=1 to N do
    		for j :=1 to M do
    			read ( a [ i, j ] );
    //Ввод матрицы B.
    	writeln ( ’Матрица B ’ );
    	for i :=1 to M do
    		for j :=1 to L do
    			read ( b [ i, j ] );
    //Формирование матрицы C.
    	for i :=1 to N do
    		for j :=1 to L do
    		begin
    {В C[i,j] будет храниться результат скалярного}
    {умножения i-й строки на j-й столбец.}
    			c [ i, j ] : = 0;
    			for k:=1 to M do
    				c [ i, j ] : = c [ i, j ]+a [ i, k ] * b [ k, j ];
    		end;
    //Вывод матрицы C=AB.
    	writeln ( ’матрица C=A*B ’ );
    	for i :=1 to N do
    	begin
    		for j :=1 to L do
    			write ( c [ i, j ] : 7 : 3, ’   ’ );
    		writeln;
    	end;
    end.
    

    Результат работы представлен на рис. 6.30.

    (рис 6.30) Результаты работы программы умножения двух матриц
    ЗАДАЧА 6.11. В матрице натуральных чисел $$A(N, M )$$ найти строки, в которых находится максимальное из простых чисел. Элементы в них упорядочить по возрастанию. Если в матрице нет простых чисел, то оставить её без изменений.

    Перед решением задачи отметим её некоторые особенности Авторы рекомендуют читателям внимательно изучить этот пример, в нём сконцентрированы практически все основные моменты, рассмотренные нами до сих пор. . В матрице может не быть простых чисел, максимальных значений может быть несколько, и при этом некоторые из них могут находиться в одной строке.

    При решении задачи нам понадобятся следующие подпрограммы:

  • Функция Prostoe, которая проверяет, является ли число P типа word простым. Она возвращает значение true, если число P — простое, и false — в противном случае. Заголовок функции имеет вид
    function Prostoe (P : word ) : Boolean;
    
  • Процедура Udal, которая из массива чисел X удаляет значения, встречающиеся более одного раза. У процедуры два параметра: массив X и его размер N, оба — параметры-переменные. Заголовок процедуры имеет вид:
    procedure Udal ( var X: massiv; var N: word );
    
    Перед описанием процедуры следует описать тип данных massiv (например, massiv = array [1..200] of word). Блок-схема процедуры Udal представлена на рис. 6.31. Удаление повторяющихся элементов происходит следующим образом. Просматриваются все элементы, начиная спервого, i-й элемент сравнивается со всеми последующими. Если, то встретился повторяющийся элемент, и мы удаляем из массива элемент с номером j. Алгоритм удаления был подробно рассмотрен в главе 5.
  • Функция Nalichie возвращает true, если число a присутствует в массиве b, и false — в противном случае. Заголовок процедуры имеет вид:
    function Nalichie ( a : word; b : massiv; N: word );
    
    Блок-схема функции представлена на рис. 6.32.
  • Процедура Vozr упорядочения массива х по возрастанию. Алгоритмы упорядочения рассматривались в главе 5. Здесь авторами использовался алгоритм сортировки методом пузырька. У процедуры Vozr два параметра: массив х (параметр-переменная) и его размер N (параметр-значение). Заголовок процедуры имеет вид:
    procedure Vozr ( var x : massiv; N: word );
    
  • (рис 6.31) Блок-схема процедуры Udal (рис 6.32) Блок-схема функции Nalichie

    Рассмотрим более подробно алгоритм решения задачи 6.11, который приведён на рис. 6.336.34.

    После ввода матрицы (блоки 1—4) предполагаем, что простых чисел нет. В логическую переменную Pr записываем false, как только встретится простое число, в переменную Pr запишем true. Количество максимальных значений среди простых чисел равно 0 (k:=0) (блок 5).

    Для проверки, является ли простым числом каждый элемент матрицы, обращаемся к функции Prostoe. Если число простое (блок 8), проверяем, первое ли это простое число в матрице (блок 9). Если это первое простое число, то переписываем его в переменную max, в переменную k записываем число 1 (количество максимумов равно 1), номер строки, в которой находится максимум, записываем в массив mas под номером k В массиве mas будут храниться номера строк, в которых находится максимум. . В связи с тем, что в матрице есть простые числа, в переменную Pr записываем true (блок 10). Если это не первое простое число, сравниваем A[i,j] с переменной max. Если A[i,j]>max (блок 11), то в переменную max запишем A[i,j], в переменную k запишем 1 (есть один максимум), в mas[k] записываем i — номер строки, где находится максимальный элемент (блок 12). Если A[i,j]=max (блок 13), то встретилось число, равное переменной max. В этом случае значение k увеличиваем на 1 и в mas[k] записываем номер строки, где находится элемент, равный max. В результате двойного цикла обработки всех элементов матрицы (блоки 6—14) в переменной max будет храниться максимальное из простых чисел, в переменной k — количество максимумов, в массиве mas из k элементов будут храниться номера строк, где находятся максимальные значение среди простых чисел матрицы. В переменной Pr хранится true, если в матрице есть простые числа, false — в противном случае. Если в матрице нет простых чисел (блок 15), выводим соответствующее сообщение (блок 16), в противном случае с помощью процедуры Udal (блок 17) удаляем из массива mas элементы, встречающиеся более одного раза Если некоторые максимальные элементы находятся в одной строке, то в массиве mas есть повторяющиеся элементы. . Затем просматриваем все строки матрицы (цикл начинается блоком 18). Если номер этой строки присутствует в массиве mas (блок 19), то переписываем текущую строку матрицы в массив b (блоки 20—21) и обращаемся к процедуре упорядочения массива по возрастанию Vozr (блок 22). Упорядоченный массив b переписываем в i-ю строку матрицы А (блоки 23—24). На последнем этапе выводим на экран матрицу А после преобразования (блоки 25—27).

    (рис 6.33) Блок-схема решения задачи 6.11 (начало) (рис 6.34) Блок-схема решение задачи 6.11 (продолжение)

    Ниже приведён листинг всей программы с подробными комментариями.

    {Тип данных massiv будет использоваться при описании процедур.}
    type
    massiv=array [ 1.. 200 ] of word;
    {Функция prostoe проверяет, является ли число N простым (true) или нет}
    {(false).}
    function prostoe (N: word ) : boolean;
    var pr : boolean; i : word;
    begin
    	if N>0 then
    	begin
    {Предполагаем, что число N - простое (pr=true).}
    		pr := true;
    {Проверяем, делится ли число N на какое либо из чисел от 2 до N/2.}
    		for i :=2 to n div 2 do
    {Если встречается число i, на которое делится N, то}
    		if N mod i =0 then
    		begin
    {число N не является простым (pr=false) и}
    			pr := false;
    {выходим из цикла.}
    			break;
    		end
    	end
    	else pr := false;
    {Имени функции присваиваем значение переменной pr.}
    	prostoe := pr;
    end;
    {Процедура udal удаляет из массива x элементы, которые встречаются}
    {более одного раза. Х, N являются параметрами-переменными, так как эти}
    {значения возвращаются в головную программу при вызове процедуры udal.}
    procedure udal ( var x : massiv; var n : word );
    var i, j,m: word;
    begin
    	i : = 1;
    {Просматриваем все элементы, начиная с первого i=1,2,...,N;i-й элемент}
    {сравниваем с последующими j=i+1,i+2,...,n.}
    	while ( i<=n ) do
    	begin
    		j := i +1;
    		while ( j<=N) do
    {Если x[i] равно x[j], то встретился повторяющийся элемент -}
    		if x [ i ]=x [ j ] then
    		begin
    {удаляем его (x[j]) из массива.}
    			for m:= j to N _1 do
    			x [m] : = x [m+ 1 ];
    {После удаления элемента количество элементов уменьшаем на 1, при этом}
    {не переходим к следующему элементу, так как после удаления под j-м}
    {номером находится уже другой элемент.}
    			N:=N-1;
    		End
    {Если x[i] не равно x[j], то переходим к следующему элементу.}
    		else j := j +1;
    		i := i +1;
    	end;
    end;
    {Функция nalichie возвращает true, если число a встречается в массиве}
    {b, false - в противном случае.}
    function nalichie ( a : word; b : massiv; n : word ) : boolean;
    var
    	pr : boolean;
    	i : word;
    begin
    {Предполагаем, что в массиве b не встречается значение a - pr=false}
    	pr := false;
    {Перебираем все элементы массива.}
    	for i :=1 to N do
    {Если очередной элемент массива b равен значению a, то в pr записываем}
    {true}
    	if b [ i ]=a then
    		begin
    		pr := true;
    {и выходим из цикла.}
    		break
    	end;
    {Имени функции присваиваем значение переменной pr.}
    	nalichie := pr
    end;
    {Процедура vozr упорядочивает массив x по возрастанию.}
    procedure vozr ( var x : massiv; n : word );
    {X является параметром-переменной, именно массив и возвращается в}
    {головную программу при вызове процедуры vozr.}
    var i, j, b : word;
    begin
    	for i :=1 to N -1 do
    		for j :=1 to N -i do
    			if x [ j ]>x [ j +1] then
    			begin
    				b:=x [ j ];
    				x [ j ] : = x [ j + 1 ];
    				x [ j +1]:=b;
    			end
    	end;
    //Начинается основная программа.
    var
    	N, M, i, j, k, max : word;
    	A: array [ 1.. 20, 1.. 20 ] of word;
    	pr, L : boolean;
    	mas, b : massiv;
    begin
    {Вводим элементы матрицы А.}
    	write ( ’N= ’ ); readln (N);
    	write ( ’M= ’ ); readln (M);
    writeln ( ’   Matrica  A ’ );
    	for i :=1 to N do
    	for j :=1 to M do
    		read (A[ i, j ] );
    {Предполагаем, что в матрице нет простых чисел.}
    	Pr:= false;
    {Количество элементов, равных максимальному, равно 0.}
    	k : = 0;
    {Перебираем все элементы в матрице.}
    	for i :=1 to N do
    	for j :=1 to M do
    	begin
    {Обращаемся к функции, которая проверяет, является ли число A[i,j]}
    {простым.}
    		L:= Prostoe (A[ i, j ] );
    {Если число простое, и}
    		if L then
    {если простое число встретилось первый раз,}
    		if not Pr then
    		begin
    {записывем в pr true,}
    			Pr:= true;
    {увеличиваем количество максимумов на 1, можно было просто написать}
    {k:=1.}
    			k:=k+1;
    {Это число записываем в переменную max. Это первое простое число, и}
    {предполагаем, что оно максимальное.}
    			max:=A[ i, j ];
    {В mas[k] записываем номер строки, где хранится число A[i,j].}
    			mas [ k ] : = i
    		end
    	else
    {Если A[i,j] - не первое простое число, то сравниваем max и текущее}
    {простое значение матрицы А.}
    		if A[ i, j ]>max then
    {Если A[I,j]> max, то}
    		begin
    {количество максимумов равно 1, т. к. встретился наибольший в данный}
    {момент элемент.}
    			k : = 1;
    {В переменную max записываем A[i,j],}
    			max:=A[ i, j ];
    {в mas[k] записываем номер строки, где хранится число A[i,j]}
    			mas [ k ] : = i
    		end
    	else
    {Если A[i,j]=max (встретился элемент, равный максимуму), то}
    if A[ i, j ]=max then
    			begin
    {количество максимумов увеличиваем на 1,}
    				k:=k+1;
    {в mas[k] записываем номер строки, где хранится число A[i,j].}
    				mas [ k ] : = i
    			end
    	end;
    {Если в pr осталось значение false,то выводим сообщение, что в матрице}
    {нет простых чисел,}
    	if not Pr then writeln ( ’В матрице A нет простых чисел ’ )
    	else
    	begin
    {иначе удаляем из массива mas номера строк, где хранятся максимумы,}
    {повторяющиеся элементы.}
    		Udal ( mas, k );
    {Перебираем все строки матрицы.}
    		for i :=1 to N do
    		begin
    			L:= Nalichie ( i, mas, k );
    {Если номер строки присутствует в массиве mas,}
    			if L then
    			begin
    {то переписываем строку в массив b,}
    				for j :=1 to M do
    				b [ j ] : =A[ i, j ];
    {упорядочиваем массив b по возрастанию.}
    				Vozr ( b,M);
    {Упорядоченный массив записываем на место i-й строки матрицы A.}
    				for j :=1 to M do
    				A[ i, j ] : = b [ j ];
    			end
    		end;
    	writeln ( ’Преобразованная матрица A ’ );
    	for i :=1 to N do
    	begin
    		for j :=1 to M do
    		write (A[ i, j ], ’   ’ );
    		writeln;
    		end
    	end
    end.
    

    Результаты работы программы приведены на рис. 6.35.

    (рис 6.35) Результаты решения задачи 6.11

    Авторы рекомендуют читателю по рассмотренным алгоритмам и консольным приложениям задач 6.7—6.11 разработать визуальные приложения, аналогичные тем, которые были разработаны для задач 6.2 и 6.6.

    В завершении этой главы рассмотрим "динамические матрицы".

    6.3 Динамические матрицы

    Понятие динамического массива можно распространить и на матрицы. Динамическая матрица представляет собой массив указателей, каждый из которых адресует одну строку (или один столбец).

    Рассмотрим описание динамической матрицы. Пусть есть типы данных massiv и указатель на него din_massiv.

    type massiv=array [ 1.. 1000 ] of real;

    din_massiv=^massiv;

    Динамическая матрица X будет представлять собой массив указателей.

    var X: array [ 1.. 100 ] of din_massiv;

    Работать с матрицей надо следующим образом:

  • Определить её размеры (пусть N — число строк, M — число столбцов).
  • Выделить память под матрицу.
  • for i :=1 to N do

    getmem(X[ i ],M * sizeof ( real ) );

    Каждый элемент статического массива X[i] — указатель на динамический массив, состоящий из M элементов типа real. В статическом массиве Х находится N указателей.

  • Для обращения к элементу динамической матрицы, расположенному в i-й строке и j-м столбце, следует использовать конструкцию языка Турбо Паскаль X[i]^[j].
  • После завершения работы с матрицей необходимо освободить память.
  • for i :=1 to N do

    freemem ( b [ i ],M * sizeof ( real ) );

    Рассмотрим работу с динамической матрицей на следующем примере.

    ЗАДАЧА 6.12. В каждой строке матрицы вещественных чисел B(N, M ) упорядочить по возрастанию элементы, расположенные между максимальным и минимальным значениями.

    Алгоритмы упорядочения рассматривались в главе 5, основные принципы работы с матрицами — в предыдущих параграфах текущей главы, поэтому в комментариях к тексту программы основное внимание уделено особенностям работы с динамическими матрицами.

    {Описываем тип данных massiv как массив 1000 вещественных чисел.}
    type massiv=array [ 1.. 1000 ] of real;
    {Указатель на массив.}
    din_massiv=^massiv;
    {Тип данных matrica - статический массив указателей, каждый элемент}
    {которого является адресом массива вещественных чисел.}
    matrica=array [ 1.. 100 ] of din_massiv;
    var
    Nmax, Nmin, i, j, n,m, k : word;
    {Описана динамическая матрица b.}
    b : matrica;
    a, max, min : real;
    begin
    {Вводим число строк N и число столбцов M.}
    write ( ’N= ’ ); readln (N);
    write ( ’M= ’ ); readln (M);
    {Выделяем память под матрицу вещественных чисел размером N на M.}
    for i :=1 to N do
    getmem( b [ i ],M * sizeof ( real ) );
    { Вводим Матрицу B. }
    writeln ( ’ Matrica B ’ );
    for i :=1 to N do
    for j :=1 to M do
    read ( b [ i ] ^ [ j ] );
    {В каждой строке находим максимальный, минимальный элементы и их номера}
    {и элементы, расположенные между ними, упорядочиваем "методом}
    {пузырька".}
    for i :=1 to N do
    begin
    {Поиск минимального, максимального элемента в i-й строке матрицы и их}
    {номеров.}
    max:=b [ i ] ^ [ 1 ];
    Nmax: = 1;
    min:=b [ i ] ^ [ 1 ];
    Nmin : = 1;
    for j :=2 to M do
    begin
    if b [ i ] ^ [ j ]>max then
    begin
    max:=b [ i ] ^ [ j ];
    nmax:= j
    end;
    if b [ i ] ^ [ j ]<min then
    begin
    min:=b [ i ] ^ [ j ];
    nmin:= j
    end;
    end;
    {Если минимальный элемент расположен позже максимального, nmin и nmax}
    {меняем местами.}
    if nmax<nmin then
    begin
    j :=nmax;
    nmax:=nmin;
    nmin:= j;
    end;
    {В i-той строке упорядочиваем элементы, расположенные между nmin и}
    {nmax, "методом пузырька".}
    j : = 1;
    while nmax-1 - j>=nmin+1 do
    begin
    for k:=nmin+1 to nmax-1 - j do
    if b [ i ] ^ [ k]>b [ i ] ^ [ k+1] then
    begin
    a:=b [ i ] ^ [ k ];
    b [ i ] ^ [ k ] : = b [ i ] ^ [ k + 1 ];
    b [ i ] ^ [ k+1]:= a;
    end;
    j := j +1;
    end;
    end;
    { Выводим преобразованную матрицу. }
    writeln ( ’Упорядоченная матрица B ’ );
    for i :=1 to N do
    begin
    for j :=1 to M do
    write ( b [ i ] ^ [ j ] : 6 : 2, ’   ’ );
    writeln
    end;
    { Освобождаем память. }
    for i :=1 to N do
    freemem ( b [ i ],M * sizeof ( real ) );
    end.
    

    Результаты работы программы представлены на рис. 6.36.

    Динамическая матрица может быть достаточно большой, фактически её размер ограничен только объемом свободной памяти.

    В заключении главы приведём задачи для самостоятельного решения.

    (рис 6.36) Результаты решения задачи 6.12
    Страницы:

    Матрица — это двумерный массив, каждый элемент которого имеет два индекса: номер строки и номер столбца.

    Объявить двумерный массив (матрицу) можно так:

    имя : array [ индекс1_нач.. индекс1_кон, индекс2_нач.. индекс2_кон ]

    of тип;

    где

  • тип определяет тип элементов массива,
  • имя — имя матрицы,
  • индекс1_нач..индекс1_кон — диапазон изменения номеров строк,
  • индекс2_нач..индекс2_кон — диапазон изменения номеров столбцов матрицы.
  • Например,

    var h : array [ 0.. 1 1, 1.. 10 ] of integer;

    Описана матрица целых чисел h, состоящая из двенадцати строк и десяти столбцов (строки нумеруются от 0 до 11, столбцы от 1 до 10).

    Существует ещё один способ описать матрицы, для этого надо создать новый тип данных:

    type

    новый_тип=array [ индекс1_нач.. индекс1_кон ] of тип;

    var

    имя : array [ индекс2_нач.. индекс2_кон ] of новый_тип;

    или

    type

    новый_тип=array [ список_диапазонов ] of тип;

    var

    имя : новый_тип;

    (рис 6.1) Построчная обработка матрицы (рис 6.2) Алгоритм обработки матрицы по столбцам

    Например:

    type
    massiv=array [ 1.. 30 ] of integer;
    matrica=array [ 0.. 15, 0.. 13 ] of real;
    var
    a, b : array [ 1.. 10 ] of massiv;
    c : matrica;
    

    В данном случае в матрицах a и b есть 10 строк и 30 столбцов, а с — матрица, в которой есть 16 строк и 14 столбцов.

    Для обращения к элементу матрицы необходимо указать её имя и в квадратных скобках через запятую номер строки и номер столбца:

    имя [ номер_строки, номер_столбца ]

    или

    имя [ номер_строки ] [ номер_столбца ]

    Например, h[2,4] Или h[2][4]. — элемент матрицы h, находящийся в строке под номером два и столбце под номером четыре.

    Для обработки всех элементов матрицы необходимо использовать два цикла. Если матрица обрабатывается построчно, то во внешнем цикле последовательно перебираются строки от первой до последней, затем во внутреннем — все (первый, второй, третий и т. д.) элементы текущей строки. При обработке элементов матрицы по столбцам внешний цикл будет перебирать столбцы, внутренний — строки. На рис. 6.1 представлена блок-схема алгоритма обработки матрицы по строкам, на рис. 6.2 — по столбцам. Здесь i — номер строки, j — номер столбца, N — количество строк, M — количество столбцов матрицы A.

    (рис 6.3) Блок-схема ввода элементов матрицы (рис 6.4) Построчный вывод матрицы

    Рассмотрим основные операции, выполняемые над матрицами при решении задач.

    6.1 Ввод-вывод матриц

    Матрицы, как и массивы, нужно вводить (выводить) поэлементно. Вначале следует ввести размеры матрицы, а затем уже в двойном цикле вводить элементы. Блок-схема ввода элементов матрицы изображена на рис. 6.3.

    Вывод можно осуществлять по строкам или по столбцам, но лучше, если элементы располагаются построчно, например,

    2 3 13 35

    5 26 76 37

    52 61 79 17

    Алгоритм построчного вывода элементов матрицы приведён на рис. 6.4.

    Об описании матриц на языке Паскаль было рассказано в разделе 5.2 главы 5, обращение к элементу $$A_{i,j}$$ матрицы можно осуществить c помощью конструкции $$A[i,j]$$ или $$A[i][j]$$.

    Рассмотрим реализацию ввода-вывода матриц в консольных приложениях.

    Для организации построчного ввода матрицы в двойном цикле по строкам и столбцам можно использовать оператор read.

    for i :=1 to N do
    for j :=1 to m do
    read (A[ i, j ] );
    

    В этом случае элементы каждой строки матрицы можно разделять символами пробела или табуляции, и только в конце строки нажимать Enter.

    ЗАДАЧА 6.1. Написать консольное приложение ввода матрицы вещественных чисел и вывода её на экран монитора.

    Ниже приведён пример консольного приложения ввода-вывода матрицы.

    var
    a : array [ 1.. 2 0, 1.. 2 0 ] of real;
    i, j, n,m: integer;
    begin
    {Ввод размеров матрицы}
    writeln ( ’Введите количество строк и столбцов матрицы A ’ );
    readln (N,M);
    {Ввод элементов матрицы.}
    writeln ( ’Введите_матрицу ’ );
    for i :=1 to N do
    for j :=1 to m do
    read (A[ i, j ] );
    {Вывод элементов матрицы.}
    writeln ( ’матрица А  ’ );
    for i :=1 to n do
    begin
    	for j :=1 to m do
    		write ( a [ i, j ] : 8 : 3, ’   ’ ); {Печатается строка.}
    	writeln {Переход на новую строку.}
    end;
    

    На рис. 6.5 представлены результаты работы программы.

    (рис 6.5) Результаты работы программы решения задачи 6.1

    Ввод матрицы также можно организовать с помощью следующего цикла.

    for i :=1 to N do
    for j :=1 to m do
    begin
    write ( ’A( ’, i, ’, ’, j, ’ )= ’ );
    	readln (A[ i, j ] )
    end;
    

    Авторы предлагают читателю самостоятельно разобраться, в чём будет отличие ввода матрицы в этом случае.

    Для ввода-вывода матриц можно использовать компонент типа TStringGrid, с которым мы познакомились в главе 5.

    В качестве примера рассмотрим следующую задачу.

    ЗАДАЧА 6.2. Составить программу транспонирования Транспонированная матрица — матрица, полученная из исходной матрицы $$A(N, M)$$ заменой строк на столбцы. матрицы$$ A$$.

    Блок-схема транспонирования матрицы приведена на рис. 6.6. При транспонировании матрицы $$A(N, M )$$ получается матрица B$$(M, N)$$.

    (рис 6.6) Блок-схема транспонирования матрицы A

    Рассмотрим частный случай транспонирования матрицы фиксированного размера A(4,3).

    На форме разместим метки Label1 и Label2 со свойствами Caption — Заданная матрица $$A$$ и Транспонированная матрица $$B$$, два компонента типа TStringGrid, изменив их свойства так, как показано в табл. 6.1, и кнопку Транспонирование матрицы.

    Окно формы приложения представлено на рис. 6.7.

    Ниже приведён текст подпрограммы с комментариями, которая будет выполняться, если пользователь щёлкнет по кнопке Транспонирование матрицы.

    Свойства компонентов StringGrid1, StringGrid2.
    Свойство StringGrid1 StringGrid2 Описание свойства
    Top 30 30 Расстояние от верхней границы таблицы до верхнего края формы
    Left 15 240 Расстояние от левой границы таблицы до левого края формы
    Height 130 130 Высота таблицы
    Width 200 200 Ширина таблицы
    ColCount 4 5 Количество столбцов
    RowCount 5 4 Количество строк
    DefaultColWidth 30 30 Ширина столбца
    DefaultRowHeight 20 20 Высота строки
    Options.goEditing true false Возможность редактирования таблицы
    (рис 6.7) Форма приложения транспонирования матрицы
    procedure TForm1. Button1Click ( Sender : TObject );
    const n=4;m=3; //Размерность матрицы A(n,m).
    var
    i, j : byte; //Индексы матрицы:
    //i - строки, j - столбцы.
    A: array [ 1.. n, 1..m] of integer; //Исходная матрица.
    B: array [ 1.. m, 1.. n ] of integer; //Транспонированная матрица.
    begin
    //Исходные данные считываются из ячеек таблицы на форме,
    //и их значения записываются в двумерный массив А.
    for i :=1 to n do //Цикл по номерам строк.
    for j :=1 to m do //Цикл по номерам столбцов.
    //Считывание элементов матрицы A из компонента StringGrid1.
    	A[ i, j ] : = StrToInt ( StringGrid1.Cells [ j, i ] );
    //Формирование транспонированной матрицы B, см. блок-схему на
    //рис. 6.6.
    for i :=1 to n do //Цикл по номерам строк.
    for j :=1 to m do //Цикл по номерам столбцов.
    B[ j, i ] : =A[ i, j ];
    //Элементы матрицы B выводятся в ячейки таблицы на форме.
    for i :=1 to n do //Цикл по номерам строк.
    for j :=1 to m do //Цикл по номерам столбцов.
    //Обращение к элементам матрицы происходит по столбцам.
    StringGrid2.Cells [ i, j ] : = IntToStr (B[ j, i ] );
    end;
    

    Результаты работы программы представлены на рис. 6.8.

    (рис 6.8) Результаты работы программы транспонирования матрицы A(3,4)

    Для демонстрации ввода-вывода матриц с помощью компонента типа TStringGrid мы рассмотрели работу с матрицами фиксированного размера A(4,3) и B(3,4). Теперь рассмотрим общий случай решения задачи транспонирования матрицы A(N,M).

    Расположим на форме следующие компоненты:

  • метку label1 с надписью "Введите размерность матрицы";
  • метку label2 с надписью "N=";
  • метку label3 с надписью "M=";
  • метку label4 с надписью "Исходная матрица А";
  • метку label5 с надписью "Преобразованная матрица В";
  • поле ввода Edit1 для ввода числа N;
  • поле ввода Edit2 для ввода числа M;
  • компонент StringGrid1 для ввода исходной матрицы A;
  • компонент StringGrid2 для хранения транспонированной матрицы B;
  • кнопку Button1 с надписью "Ввод" для ввода размеров матрицы А;
  • кнопку Button2 с надписью "Очистить" для очистки содержимого матриц;
  • кнопку Button3 с надписью "Транспонирование" для решения задачи транспонирования матрицы А;
  • кнопку Button4 с надписью "Выход из программы" для завершения работы программы.
  • Можно разместить компоненты на форме так, как показано на рис. 6.9.

    (рис 6.9) Окно формы решения задачи транспонирования матрицы A(N, M ) (рис 6.10) Стартовое окно программы транспонирования матрицы A(N, M )

    Установим свойство видимости (Visible) в False у компонентов метки label4, label5, StringGrid1, StringGrid2, кнопки Button2 и Button3. После этого при запуске программы будут видны только компоненты, отвечающие за ввод размеров матрицы, и кнопка Выход из программы (см. рис. 6.10) Свойству формы Caption присвоено значение Транспонирование матрицы. . Матрицы A и B, их размеры N, M объявим глобально.

    type
    	{ TForm1 }
    {Описание формы}
    	TForm1 = class (TForm)
    		Button1 : TButton;
    		Button2 : TButton;
    		Button3 : TButton;
    		Button4 : TButton;
    		Edit1 : TEdit;
    		Edit2 : TEdit;
    		Label1 : TLabel;
    		Label2 : TLabel;
    		Label3 : TLabel;
    		Label4 : TLabel;
    		Label5 : TLabel;
    		StringGrid1 : TStringGrid;
    		StringGrid2 : TStringGrid;
    	private
    	{private declarations}
    	public
    	{public declarations}
    end;
    var
    {Матрицы A,B}
    	A,B: array [ 1.. 25, 1.. 25 ] of integer;
    {и их размеры}
    	N,M: integer;
    	Form1 : TForm1;
    

    Обработчик кнопки Выход из программы стандартен и представлен ниже.

    procedure TForm1. Button4Click ( Sender : TObject );
    begin
    	Close;
    end;
    

    Теперь напишем обработчик кнопки Ввод, который должен вводить и проверять корректность введения размеров матрицы, устанавливать свойства компонентов StringGrid1 и StringGrid2 (количество строк и столбцов), делать видимым компонент StringGrid1, кнопку Транспонирование, невидимыми компоненты, отвечающие за ввод размеров матрицы (метки label1, label2, label3, поля ввода Edit1 и Edit2, кнопку Ввод ).

    procedure TForm1. Button1Click ( Sender : TObject );
    var i : byte; kod_n, kod_m, kod : integer;
    begin
    //Ввод размерности матрицы.
    //Символьная информация преобразовывается в числовую и
    //записывается в
    	Val ( Edit1. Text,N, kod_m ); //переменную M
    	Val ( Edit2. Text,M, kod_n ); //и переменную N.
    //Если преобразование прошло успешно и введенные размеры
    //удовлетворяют описанию
    //матриц A и B,
    	if ( kod_n=0) and (kod_m=0) and (N>0) and (N<26) and (M>0)
    		and (M<26)
    	then
    //то
    	begin
    //визуализируется первая матрица,
    		StringGrid1. Visible := true;
    		Label4. Visible := true; //соответствующая ей надпись,
    		Button2. Visible := true; //кнопки "Очистить"
    		Button3. Visible := true; //и "Транспонирование".
    		with StringGrid1 do
    		begin
    //Определяем число строк (RowCount) и столбцов(ColCount) в
    //компоненте StringGrid1.
    			ColCount :=M+1;
    			RowCount:=N+1;
    //и нумеруем строки и столбцы матрицы.
    			for i :=1 to RowCount-1 do
    			Cells [ 0, i ] : = IntToStr ( i );
    			for i :=1 to ColCount -1 do
    			Cells [ i, 0 ] : = IntToStr ( i );
    		end;
    StringGrid2. ColCount :=N+1;
    StringGrid2. RowCount:=M+1;
    end
    	else
    	begin
    //При некорректном вводе выдаётся соответствующее сообщение.
    	MessageDlg ( ’Размеры матрицы введены не верно ! ’, MtInformation,
    [mbOk ], 0 );
    //Устанавливаются стартовые параметры в поля ввода.
    	Edit1. Text := ’ 4 ’;
    	Edit2. Text := ’ 3 ’;
    end;
    end;
    

    Теперь напишем обработчик кнопки Транспонирование. При щелчке по этой кнопке становится видимым компонент StrigGrid2, предназначенный для хранения транспонированной матрицы B, соответствующая ему надпись (label5), формируется матрица B. Матрица B выводится в компонент StringGrid2. Кнопка Ввод становится невидимой. Текст обработчика приведён ниже.

    procedure TForm1. Button2Click ( Sender : TObject );
    var i, j : integer;
    begin
    //Визуализируется вторая матрица,
    //соответствующая ей надпись.
    StringGrid2. Visible := true;
    label5. Visible := true;
    for i :=1 to N do //Цикл по номерам строк.
    for j :=1 to M do //Цикл по номерам столбцов.
    //Считывание элементов матрицы A из компонента StringGrid1.
    A[ i, j ] : = StrToInt ( StringGrid1.Cells [ j, i ] );
    with StringGrid2 do
    begin
    for i :=1 to RowCount-1 do //Нумеруются строки
    Cells [ 0, i ] : = IntToStr ( i );
    for i :=1 to ColCount -1 do //и столбцы компонента StringGrid2, в
    Cells [ i, 0 ] : = IntToStr ( i ); //котором отображается матрица B.
    end;
    //Формирование транспонированной матрицы B.
    for i :=1 to N do //Цикл по номерам строк.
    for j :=1 to M do //Цикл по номерам столбцов.
    B[ j, i ] : =A[ i, j ];
    //Элементы матрицы B выводятся в ячейки таблицы на форме.
    for i :=1 to n do //Цикл по номерам строк.
    for j :=1 to m do //Цикл по номерам столбцов.
    //Обращение к элементам матрицы происходит по столбцам.
    StringGrid2.Cells [ i, j ] : = IntToStr (B[ j, i ] );
    Buuton1.Visible := False;
    end;
    

    Осталось написать обработчик события при нажатии на кнопку Очистить. При щелчке по этой кнопке должно происходить следующее:

  • очистка содержимого компонентов StringGrid1, StringGrid2;
  • компоненты StringGrid1, StringGrid2 и соответствующие им метки labe4 и label5, а также кнопки Транспонировать и Очистить становятся невидимыми;
  • становится видимой кнопка Ввод;
  • в поля ввода записываются начальные значения размеров матрицы (N=4, M=3).
  • Текст обработчика кнопки Очистить с комментариями приведен ниже:

    procedure TForm1. Button3Click ( Sender : TObject );
    var i, j : integer;
    begin
    //Очистка компонента StringGrid1.
    	with StringGrid1 do
    		for i :=1 to RowCount-1 do
    		for j :=1 to ColCount -1 do
    			Cells [ j, i ] : = ’ ’;
    //Очистка компонента StringGrid2.
    	with StringGrid2 do
    		for i :=1 to RowCount-1 do
    		for j :=1 to ColCount -1 do
    		Cells [ j, i ] : = ’ ’;
    //Делаем невидимыми компоненты StringGrid1, StringGrid2,
    //labe4, label5.
    	StringGrid1. Visible := False;
    	StringGrid2. Visible := False;
    	label4. Visible := False;
    	label5. Visible := False;
    //Делаем невидимыми кнопки "Транспонировать" и "Очистить".
    	Button2. Visible := False;
    	Button3. Visible := False;
    //Делаем видимой кнопку "Ввод".
    	Button1. Visible :=True;
    //Запись начальных значений размеров матрицы
    //(N=4, M=3).
    	Edit1. Text := ’ 4 ’;
    	Edit2. Text := ’ 3 ’;
    end;
    

    Мы получили работающую программу для транспонирования матрицы. На рис. 6.11 представлены результаты транспонирования матрицы A(2,4).

    Обратите внимание на использование оператора присоединения

    with имя_компонента do оператор;

    который упрощает доступ к свойствам компонента. Внутри оператора With имя компонента для обращения к его свойствам можно не использовать.

    Например, для очистки элементов матрицы A вместо операторов

    for i :=1 to StringGrid1. RowCount-1 do
    	for j :=1 to StringGrid1. ColCount -1 do
    		StringGrid1.Cells [ j, i ] : = ’ ’;
    

    был использован оператор

    with StringGrid1 do
    	for i :=1 to RowCount-1 do
    		for j :=1 to ColCount -1 do
    			Cells [ j, i ] : = ’ ’;
    

    Рассмотрим несколько задач обработки матриц. Для их решения напомним читателю некоторые свойства матриц (рис. 6.12):

    (рис 6.11) Транспонирование матрицы A(2,4) (рис 6.12) Свойства элементов матрицы
  • если номер строки элемента совпадает с номером столбца ($$i = j$$), это означает, что элемент лежит на главной диагонали матрицы;
  • если номер строки превышает номер столбца ($$i > j$$), то элемент находится ниже главной диагонали;
  • если номер столбца больше номера строки ($$i < j$$), то элемент находится выше главной диагонали;
  • элемент лежит на побочной диагонали, если его индексы удовлетворяют равенству $$i + j - 1 = n$$;
  • неравенство $$i + j - 1 < n$$ характерно для элемента, находящегося выше побочной диагонали;
  • соответственно, элементу лежащему ниже побочной диагонали, соответствует выражение $$i + j - 1 > n$$.
  • 6.2 Алгоритмы и программы работы с матрицами

    Рассмотри несколько примеров решения задач обработки матриц.

    ЗАДАЧА 6.3. Найти сумму элементов матрицы, лежащих выше главной диагонали (см. рис. 6.13). (рис 6.13) Рисунок к задаче 6.3

    Рассмотрим два алгоритма решения данной задачи.

    Первый алгоритм решения данной задачи (см. рис. 6.14) построен следующим образом. Вначале переменная S для накапливания суммы обнуляется (S:=0). Затем с помощью двух циклов (первый по строкам, второй по столбцам) перебираются все элементы матрицы, но накапливание суммы происходит только в том случае, если этот элемент находится выше главной диагонали (если выполняется свойство i<j).

    Текст консольного приложения с комментариями приведён ниже.

    var
    a : array [ 1.. 15, 1.. 10 ] of real;
    i, j, n,m: integer; s : real;
    begin
    writeln ( ’введите размеры матрицы ’ );
    writeln ( ’ n - количество строк,  m - количество столбцов ’ );
    readln ( n,m);
    writeln ( ’Введите матрицу A ’ );
    for i :=1 to n do
    for j :=1 to m do
    read ( a [ i, j ] );
    s : = 0;
    for i :=1 to n do
    for j :=1 to m do
    if j>i then {Если элемент лежит выше главной диагонали, то}
    s := s+a [ i, j ]; {наращиваем сумму.}
    writeln ( ’матрица А ’ );
    for i :=1 to n do
    begin
    for j :=1 to m do
    {Здесь важен формат, особенно общая ширина поля!}
    write ( a [ i, j ] : 8 : 3, ’   ’ );
    writeln
    end;
    writeln ( ’сумма элементов  матрицы ’, s : 8 : 3 );
    end.
    
    (рис 6.14) Блок-схема задачи 6.3 (алгоритм 1) (рис 6.15) Блок-схема задачи 6.3 (алгоритм 2)

    Результаты работы программы представлены на рис. 6.16.

    Второй алгоритм решения этой задачи представлен на рис. 6.15.

    В нём проверка условия i<j не выполняется, но, тем не менее, в нём также суммируются элементы матрицы, находящиеся выше главной диагонали. Для пояснения функционирования алгоритма обратимся к рисунку 6.13. В первой строке заданной матрицы необходимо сложить все элементы, начиная со второго. Во второй — все, начиная с третьего, в i–й строке процесс суммирования начнётся с (i+1)-го элемента и так далее. Таким образом, первый цикл работает от 1 до N, а второй от i+1 до M.

    Предлагаем читателю самостоятельно составить программу, соответствующую описанному алгоритму.

    (рис 6.16) Результаты работы программы решения задачи 6.3 ЗАДАЧА 6.4. Вычислить количество положительных элементов квадратной матрицы $$A$$, расположенных по её периметру и на диагоналях. (рис 6.17) Рисунок к условию задачи 6.4

    В квадратной матрице число строк равно числу столбцов. Прежде чем приступить к решению задачи, рассмотрим рисунок 6.17, на котором изображена схема диагоналей квадратных матриц различной размерности.

    Из рисунка видно, что нет необходимости рассматривать все элементы матрицы. Достаточно рассмотреть элементы, расположенные в первой и последней строках, в первом и последнем столбцах, а также на диагоналях квадратной матрицы. Все эти элементы отмечены на рис. 6.17, причём чёрным цветом выделены элементы, которые принадлежат строкам, столбцам и диагоналям. Например, элемент $$A_{1,1}$$ принадлежит первой строке, первому столбцу, и главной диагонали матрицы, элемент $$A_{N,N}$$ находится в последней строке, последнем столбце и принадлежит главной диагонали. Кроме того, если $$N$$ — число нечётное (на рисунке 6.17 эта матрица расположена слева), то существует элемент с индексом (N div 2 + 1, N div 2 + 1), который находится на пересечении главной и побочной диагоналей. При чётном значении $$N$$ (матрица справа на рис. 6.17) диагонали не пересекаются.

    Рассмотрим алгоритм решения задачи. Для обращения к элементам главной диагонали вспомним, что номера строк этих элементов всегда равны номерам столбцов. Поэтому если параметр i изменяется циклически от 1 до N, то $$A_{i,i}$$ — элемент главной диагонали. Воспользовавшись свойством, характерным для элементов побочной диагонали, получим: $$i+j -1 = N \to j = N - i+1$$, следовательно, для строк i=1,2,...,N элемент $$A_{i,N-i+1}$$ — элемент побочной диагонали. Элементы, находящиеся по периметру матрицы записываются следующим образом: $$A_{1,i}$$ — элементы, расположенные в первой строке (i=1,2,...,N), $$A_{N,i}$$ — элементы, расположенные в последней строке (i=1,2,...,N) и, соответственно, $$A_{i,1}$$ — элементы, расположенные в первом столбце (i=1,2,...,N), $$A_{i,N}$$ — в последнем столбце (i=1,2,...,N).

    Алгоритм обработки построим следующим образом: сначала обработаем элементы, расположенные на диагоналях квадратной матрицы. Для этого необходимо в каждой строке (i=1,2,...,N) проверять знак элементов$$ A_{i,i}$$ и $$A_{i,N-i+1}$$.

    for i :=1 to N do
    	begin
    		if ( a [ i, i ] >0) then k:=k+1;
    		if a [ i,N - i +1]>0 then k:=k+1;
    	end;
    

    Так как угловые элементы матрицы уже учтены при проверке диагональных элементов, при обработке элементов, расположенных по периметру матрицы, их учитывать уже не нужно. Поэтому надо перебрать элементы со второго до предпоследнего в первой и последней строке, в первом и последнем столбце.

    for i :=2 to N - 1 do
    	begin
    {Если элемент находится в первой строке.}
    	if ( a [ 1, i ] >0) then k:=k+1;
    {Если элемент находится в последней строке.}
    	if ( a [N, i ] >0) then k:=k+1;
    {Если элемент находится в первом столбце.}
    	if ( a [ i,1] >0) then k:=k+1;
    {Если элемент находится в последнем столбце.}
    	if ( a [ i,N] >0) then k:=k+1;
    end;
    

    Затем нужно проверить, не был ли элемент, находящийся на пересечении диагоналей, подсчитан дважды. Это могло произойти только в том случае, если N — нечётно и элемент, расположенный на пересечении диагоналей На пересечении диагоналей находится элемент с индексами (N div 2 + 1, N div 2 + 1). , положителен.

    if (N mod 2 <> 0) and ( a [ n div 2 + 1, n div 2 + 1 ] > 0) then
    k:=k -1;
    

    Ниже приведён полный текст консольного приложения решения задачи 6.4 с комментариями.

    var a : array [ 1.. 10, 1.. 10 ] of integer;
    	i, j, N, k : integer;
    begin
    	write ( ’N= ’ );
    	readln (N);
    //Ввод исходной матрицы.
    	writeln ( ’Введите матрицу A ’ );
    	for i :=1 to N do
    		for j :=1 to N do
    			read ( a [ i, j ] );
    //Вывод исходной матрицы.
    	writeln ( ’Была введена матрица A: ’ );
    	for i :=1 to N do
    	begin
    		for j :=1 to N do
    			write ( a [ i, j ], ’   ’ );
    		writeln;
    	end;
    	k : = 0;
    //Обработка элементов, расположенных на диагоналях матрицы.
    	for i :=1 to N do
    	begin
    		if ( a [ i, i ] >0) then k:=k+1;
    		if a [ i,N-i +1]>0 then k:=k+1;
    end;
    //Обработка элементов, расположенных по периметру матрицы.
    	for i :=2 to N - 1 do
    	begin
    		if ( a [ 1, i ] >0) then k:=k+1;
    		if ( a [N, i ] >0) then k:=k+1;
    		if ( a [ i,1] >0) then k:=k+1;
    		if ( a [ i,N] >0) then k:=k+1;
    end;
    {Если элемент, находящийся на пересечении диагоналей, подсчитан дважды,}
    {то уменьшить вычисленное значение к на один.}
    	if ( n mod 2<>0) and ( a [N div 2+1,N div 2+1]>0) then
    k:=k _1;
    	writeln ( ’ k= ’, k );
    end.
    

    На рис. 6.18 представлены результаты работы программы решения задачи 6.4.

    (рис 6.18) Результаты решения задачи 6.5 ЗАДАЧА 6.5. Проверить, является ли заданная квадратная матрица единичной.

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

    $$\left(\begin{matrix} 1000\\ 0100\\ 0010\\ 0001 \end{matrix}\right)$$

    Решать задачу будем так. Предположим, что матрица единичная (pr:=true) и попытаемся доказать обратное. В двойном цикле по по строкам (i:=1,2,...,N) и по по столбцам (j:=1,2,...,N) перебираем все элементы матрицы. Если диагональный элемент ($$i = j $$) не равен единице или элемент, расположенный вне диагонали ($$i \not = j$$), не равен нулю Воспользовавшись логическими операциями and и or это сложное условие можно записать так: $$if ((i=j) and (a[i,j]<>1)) or ((i<>j) and (a[i,j]<>0)) then...$$ , то в логическую переменную pr записываем значение false и прекращаем проверку (аварийно покидаем цикл). После цикла проверяем значение pr. Если переменная pr по прежнему равна true, то матрица единичная; в противном случае она таковой не является. Блок-схема алгоритма решения задачи представлена на рис. 6.19.

    (рис 6.19) Блок-схема алгоритма решения задачи 6.5
    program pr_6_5;
    var a : array [ 1.. 10, 1.. 10 ] of real;
    	i, j, n : integer;
    	pr : boolean;
    begin
    	writeln ( ’Введите размер матрицы ’ );
    	readln ( n );
    	writeln ( ’Введите матрицу ’ );
    	for i :=1 to n do
    		for j :=1 to n do
    		read ( a [ i, j ] );
    {Предположим, что матрица единичная,}
    {и присвоим логической переменной значение "истина".}
    {Если значение этой переменной при выходе из цикла не изменится, это}
    {будет означать, что матрица действительно единичная.}
    	pr := true;
    	for i :=1 to n do
    		for j :=1 to n do
    		if ( ( i=j ) and ( a [ i, j ]<>1)) or ( ( i <>j ) and ( a [ i, j ]<>0))
    		  then
    {Если элемент лежит на главной диагонали и не равен единице или элемент}
    {лежит вне главной диагонали и не равен нулю, то}
    begin
    {логической переменной присвоить значение "ложь"}
    {это будет означать, что матрица единичной не является,}
    pr := false;
    {выйти из цикла.}
    break;
    end;
    {Проверка значения логической переменной и печать результата.}
    if pr then
    writeln ( ’Матрица единичная ’ )
    else writeln ( ’Матрица не является единичной ’ );
    end.
    
    ЗАДАЧА 6.6. Преобразовать исходную матрицу так, чтобы последний элемент каждого столбца был заменён разностью минимального и максимального элемента в этом же столбце.

    Для решения данной задачи необходимо найти в каждом столбце максимальный и минимальный элементы, после чего в последний элемент столбца записать их разность. Блок-схема алгоритма решения приведена на рис. 6.20.

    Ниже приведён текст консольного приложения с комментариями.

    program pr_6_6;
    	var a : array [ 1.. 25, 1.. 25 ] of real;
    	i, j, n,m: integer;
    	max, min : real;
    	begin
    {Ввод размеров матрицы.}
    	writeln ( ’Введите размеры матрицы ’ );
    	readln ( n,m);
    {Ввод исходной матрицы.}
    	writeln ( ’Введите матрицу ’ );
    	for i :=1 to n do
    		for j :=1 to m do
    			read ( a [ i, j ] );
    {Последовательно перебираем все столбцы матрицы.}
    	for j :=1 to m do
    	begin
    {Максимальным и минимальным объявляем первый элемент текущего (j-го)}
    {столбца матрицы.}
    	max:=a [ 1, j ];
    	min:=a [ 1, j ];
    {Последовательно перебираем все элементы в текущем (j-м) столбце}
    {матрицы.}
    	for i :=2 to n do
    	begin
    {Если текущий элемент больше максимального, то его и объявляем}
    {максимальным.}
    		if a [ i, j ]>max then max:=a [ i, j ];
    {Если текущий элемент меньше минимального, то его и объявляем}
    {минимальным.}
    		if a [ i, j ]<min then min:=a [ i, j ];
    	end;
    {В последний элемент столбца записываем разность между максимальным и}
    {минимальным элементами столбца.}
    		a [ n, j ] : =max _min;
    	end;
    {Вывод преобразованной матрицы.}
    	writeln ( ’Преобразованная матрица ’ );
    	for i :=1 to n do
    		begin
    			for j :=1 to m do
    				write ( a [ i, j ] : 7 : 3, ’   ’ );
    		writeln;
    	end;
    end.
    
    (рис 6.20) Блок-схема алгоритма решения задачи 6.6

    Теперь давайте создадим визуальное приложение, реализующее рассмотренный алгоритм. За основу возьмём форму (см. рис. 6.9) и проект транспонирования матрицы A(N,M), разработанные для задачи 6.2. Окно формы несколько изменим (рис. 6.9). Кнопку Транспонирование переименуем в Преобразование матрицы, а свойством Caption метки label5 установим Преобразованная матрица A. Кроме того, изменим свойство Caption формы (см. рис. 6.21). Окно изменённой формы представлено на рис. 6.21.

    Обработчики кнопок Ввод, Очистить, Выход из программы изменятся мало. Рассмотрим алгоритм работы обработчика кнопки Преобразование матрицы. В этом обработчике будет производиться считывание матрицы из компонента StringGrid1, преобразование матрицы A по алгоритму, представленному на рис. 6.20, вывод преобразованной матрицы в компонент StringGrid2.

    (рис 6.21) Окно формы решения задачи 6.6

    Текст модуля визуального приложения решения задачи 6.6 с комментариями приведён ниже.

    unit Unit1;
    {$mode objfpc}{$H+}
    interface
    uses
    	Classes, SysUtils, LResources, Forms, Controls, Graphics,
    	Dialogs, StdCtrls, Grids;
    //Описание формы
    type
    	{ TForm1 }
    	TForm1 = class (TForm)
    	Button1 : TButton;
    	Button2 : TButton;
    	Button3 : TButton;
    	Button4 : TButton;
    	Edit1 : TEdit;
    	Edit2 : TEdit;
    	Label1 : TLabel;
    	Label2 : TLabel;
    	Label3 : TLabel;
    	Label4 : TLabel;
    	Label5 : TLabel;
    	StringGrid1 : TStringGrid;
    	StringGrid2 : TStringGrid;
    	procedure Button1Click ( Sender : TObject );
    	procedure Button2Click ( Sender : TObject );
    	procedure Button3Click ( Sender : TObject );
    	procedure Button4Click ( Sender : TObject );
    private
    	{private declarations}
    public
    	{public declarations}
    	end;
    var
    	A: array [ 1.. 2 5, 1.. 2 5 ] of real;
    	N,M: integer;
    	Form1 : TForm1;
    implementation
    { TForm1 }
    //Обработчик кнопки "Выход из программы".
    procedure TForm1. Button4Click ( Sender : TObject );
    begin
    	Close;
    end;
    //Обработчик первой кнопки — кнопки ввода размерности матрицы.
    procedure TForm1. Button1Click ( Sender : TObject );
    var i : byte; kod_n, kod_m, kod : integer;
    begin
    //Ввод размерности матрицы.
    //Символьная информация преобразовывается в числовую и
    //записывается в переменные N и M.
    	Val ( Edit1. Text,N, kod_m );
    	Val ( Edit2. Text,M, kod_n );
    	//Если преобразование прошло успешно и введенные размеры
    //удовлетворяют описанию матриц A и B,
    	if ( kod_n=0) and (kod_m=0) and (N>0) and (N<26) and (M>0)
    		and (M<26)
    then
    //то
    	begin
    //визуализируется первая матрица,
    	StringGrid1. Visible := true;
    //соответствующая ей надпись,
    	Label4. Visible := true;
    //кнопки "Очистить"
    	Button2. Visible := true;
    //и "Транспонирование"
    	Button3. Visible := true;
    	with StringGrid1 do
    		begin
    			ColCount :=M+1;
    			RowCount:=N+1;
    //и нумеруются строки и
    			for i :=1 to RowCount-1 do
    				Cells [ 0, i ] : = IntToStr ( i );
    //столбцы первой таблицы.
    			for i :=1 to ColCount -1 do
    				Cells [ i, 0 ] : = IntToStr ( i );
    		end;
    		StringGrid2. ColCount :=M+1;
    		StringGrid2. RowCount:=N+1;
    	end
    	else
    	begin
    //При некорректном вводе выдается соответствующее сообщение.
    		MessageDlg ( ’Размеры матрицы введены неверно! ’,
    		MtInformation, [ mbOk ], 0 );
    //Устанавливаются стартовые параметры в поля ввода.
    		Edit1. Text := ’ 4 ’;
    		Edit2. Text := ’ 3 ’;
    	end;
    end;
    //Обработчик кнопки "Преобразование матрицы".
    procedure TForm1. Button2Click ( Sender : TObject );
    var i, j : integer;
    	max, min : real;
    begin
    	StringGrid2. Visible := true;
    	label5. Visible := true;
    	for i :=1 to N do //Цикл по номерам строк.
    		for j :=1 to M do //Цикл по номерам столбцов.
    //Считывание элементов матрицы A из компонента StringGrid1,
    			A[ i, j ] : = StrToFloat ( StringGrid1.Cells [ j, i ] );
    			with StringGrid2 do
    			begin
    				for i :=1 to RowCount-1 do //и нумеруются
    					Cells [ 0, i ] : = IntToStr ( i ); //строки и
    				for i :=1 to ColCount -1 do //столбцы второй матрицы.
    					Cells [ i, 0 ] : = IntToStr ( i );
    			end;
    //Решение задачи 6.6.
    	for j :=1 to m do
    	begin
    {Максимальным и минимальным объявляем первый элемент текущего (j-го)}
    {столбца матрицы.}
    	max:=a [ 1, j ];
    	min:=a [ 1, j ];
    {Последовательно перебираем все элементы в текущем (j-м) столбце}
    {матрицы.}
    		for i :=2 to n do
    		begin
    {Если текущий элемент больше максимального, то его и объявляем}
    {максимальным.}
    			if a [ i, j ]>max then max:=a [ i, j ];
    {Если текущий элемент меньше минимального, то его и объявляем}
    {минимальным.}
    			if a [ i, j ]<min then min:=a [ i, j ];
    		end;
    {В последний элемент столбца записываем разность между максимальным и}
    {минимальным элементами столбца.}
    	a [ n, j ] : =max _min;
    	end;
    //Элементы преобразованной матрицы A выводятся в ячейки
    //таблицы на форме.
    	for i :=1 to N do //Цикл по номерам строк.
    		for j :=1 to M do //Цикл по номерам столбцов.
    //Запись элемента преобразованной матрицы A в ячейку StringGrid2.
    		StringGrid2.Cells [ j, i ] : = FloatToStr (A[ i, j ] );
    //Делаем первую кнопку невидимой.
    	Button1. Visible := False;
    end;
    //Обработчик кнопки "Очистить"
    procedure TForm1. Button3Click ( Sender : TObject );
    	var i, j : integer;
    begin
    //Очистка компонента StringGrid1.
    	with StringGrid1 do
    	for i :=1 to RowCount-1 do
    		for j :=1 to ColCount -1 do
    			Cells [ j, i ] : = ’ ’;
    //Очистка компонента StringGrid2.
    	with StringGrid2 do
    		for i :=1 to RowCount-1 do
    			for j :=1 to ColCount -1 do
    				Cells [ j, i ] : = ’ ’;
    //Делаем невидимыми компоненты StringGrid1, StringGrid2,
    //labe4, label5.
    	StringGrid1. Visible := False;
    	StringGrid2. Visible := False;
    	label4.Visible := False;
    	label5.Visible := False;
    //Делаем невидимыми кнопки "Транспонировать" и "Очистить".
    	Button2. Visible := False;
    	Button3. Visible := False;
    //Делаем видимой кнопку "Ввод".
    	Button1. Visible :=True;
    //Запись начальных значений размеров матрицы (N=4,
    //M=3).
    	Edit1. Text := ’ 4 ’;
    	Edit2. Text := ’ 3 ’;
    end;
    initialization
    	{$I unit1.lrs}
    end.
    

    На рис. 6.22 представлено окно с результатами решения задачи.

    ЗАДАЧА 6.7. Поменять местами $$n$$-й и $$r$$-й столбцы матрицы $$A(K, M )$$.

    Задача сводится к обмену $$n$$-го и $$r$$-го элемента во всех строках матрицы.

    Блок-схема приведена на рис. 6.23.

    Ниже приведён листинг консольного приложения с комментариями.

    type matrica=array [ 1.. 15, 1.. 15 ] of real;
    var
    a : matrica;
    i, j, k,m, n, r : byte; b : real;
    begin
    //Ввод размеров матрицы.
    write ( ’ k= ’ ); readln ( k );
    write ( ’m= ’ ); readln (m);
    //Ввод матрицы A.
    writeln ( ’Матрица A ’ );
    for i :=1 to k do
    for j :=1 to m do
    read ( a [ i, j ] );
    //Ввод номеров столбцов матрицы, подлежащих обмену.
    repeat
    write ( ’ n= ’ );
    readln ( n );
    write ( ’ r= ’ );
    readln ( r );
    {Ввод считается верным, если n и r не больше m и не равны друг другу.}
    until ( n<=m) and ( r<=m) and ( n<>r );
    {Элементы столбца с номером r заменить элементами столбца с номером n.}
    for i :=1 to k do
    begin
    b:=a [ i, n ];
    a [ i, n ] : = a [ i, r ];
    a [ i, r ] : = b
    end;
    writeln ( ’Преобразованная матрица A ’ );
    for i :=1 to k do
    begin
    for j :=1 to m do
    write ( a [ i, j ] : 7 : 3, ’   ’ );
    writeln;
    end;
    end.
    
    (рис 6.22) Результаты решения задачи 6.6 (рис 6.23) Блок-схема алгоритма решения задачи 6.7

    Результаты работы программы приведены на рис. 6.24.

    (рис 6.24) Результаты решения задачи 6.7 ЗАДАЧА 6.8. Преобразовать матрицу $$A(m, n)$$ так, чтобы строки с нечётными индексами были упорядочены по убыванию, c чётными — по возрастанию.

    Каждая строка матрицы является одномерным массивом. Поэтому для упорядочения строки или столбца можно использовать обычные алгоритмы сортировки массивов. При решении задачи необходимо последовательно просматривать все строки матрицы, если номер строки нечётный, то сортируем строку методом пузырька по убыванию, иначе — по возрастанию. Блок-схема этого алгоритма представлена на рис. 6.25.

    (рис 6.25) Блок-схема алгоритма решения задачи 6.8

    Ниже представлено консольное предложение для решения этой задачи с комментариями.

    var a : array [ 1.. 15, 1.. 15 ] of real;
    	j, i, k,m, n : byte; b : real;
    begin
    //Ввод размеров матрицы.
    	writeln ( ’введите m и n ’ );
    readln (m, n );
    //Ввод матрицы.
    writeln ( ’Матрица А ’ );
    for i :=1 to m do
    for j :=1 to n do
    read ( a [ i, j ] );
    //Преобразование матрицы.
    for i :=1 to m do
    if ( i mod 2)=0 then {Если номер строки четный, то}
    begin {упорядочить ее элементы по возрастанию.}
    {Упорядочение строки матрицы методом пузырька по возрастанию.}
    for k:=1 to n-1 do
    for j :=1 to n-k do
    if a [ i, j ] > a [ i, j +1] then
    begin
    b:=a [ i, j ];
    a [ i, j ] : = a [ i, j + 1 ];
    a [ i, j +1]:=b;
    end
    end
    else {Если номер строки нечетный, то упорядочить ее элементы по}
    {убыванию.}
    {Упорядочение строки матрицы методом пузырька по убыванию.}
    for k:=1 to n-1 do
    for j :=1 to n-k do
    if a [ i, j ] < a [ i, j +1] then
    begin
    b:=a [ i, j ];
    a [ i, j ] : = a [ i, j + 1 ];
    a [ i, j +1]:=b;
    end;
    //Вывод преобразованной матрицы.
    writeln ( ’преобразованная матрица A ’ );
    for i :=1 to m do
    begin
    for j :=1 to n do
    write ( a [ i, j ] : 7 : 3, ’   ’ );
    writeln
    end
    end.
    

    На рис. 6.26 приведены результаты работы программы.

    (рис 6.26) Результаты решения задачи 6.8 ЗАДАЧА 6.9. Задана матрица целых положительных чисел $$A(n, m)$$. Сформировать вектор $$P (n)$$, в который записать сумму простых чисел каждой строки матрицы в четверичной системе счисления; если в строке нет простых чисел, в соответствующий элемент массива записать число 0.

    Для решения этой задачи нам понадобятся функции проверки, является ли число простым, и перевода целого числа в четверичную систему счисления. Алгоритм проверки, является ли число простым, уже неоднократно рассматривался в книге. Функция этой проверки подробно рассматривалась в главе 5 при решении задачи 5.7. Поэтому здесь просто приведем её текст.

    function prostoe (N: integer ) : boolean;
    var i : integer;
    	pr : boolean;
    begin
    if N<1 then pr := false
    else
    begin
    	pr := true;
    	for i :=2 to N div 2 do
    		if (N mod i = 0) then
    		begin
    			pr := false;
    			break;
    	end;
    end;
    prostoe:= pr;
    end;
    

    В этой же главе 5 мы рассматривали алгоритм (рис. 5.42) и функцию перевода (function perevod(N:real;P:word;kvo:word):real;) вещественного числа в $$p$$-чную систему счисления (задача 5.10). Нужная нам функция перевода целого числа в четверичную систему счисления является частным случаем рассмотренной ранее функции perevod. Ниже приведён текст функции perevod4, которая переводит целое положительное число в четверичную систему счисления.

    {Функция перевода целого числа N в четверичную систему счисления.}
    function perevod4 (N: word ) : word;
    	var s1, i, q, ost : word;
    begin
    {В переменной s1 мы будем собирать число в четверичной системе}
    {счисления.}
    	s1 : = 0;
    {В переменной q будем последовательно хранить степени десяти; вначале}
    {туда записываем 1 - десять в 0 степени, а затем в цикле будем}
    {последовательно умножать q на 10.}
    q : = 1;
    {Перевод целого числа, пока число не станет равным 0.}
    	while (N<>0) do
    	begin
    {Вычисляем ost - очередной разряд числа, как остаток от деления N на 4}
    {(основание системы счисления).}
    	ost :=N mod 4;
    {Очередной разряд числа умножаем на 10 в степени i и добавляем к}
    {формируемому числу s1.}
    	s1 := s1+ost * q;
    {Уменьшаем число N в 4 раза путем целочисленного деления на 4.}
    	N1:=N1 div 4;
    {Формируем следующую степень десятки.}
    	q:=q * 10;
    end;
    //Возвращаем число в четверичной системе счисления.
    	perevod := s1;
    end;
    

    В каждой строке надо найти сумму простых чисел, а затем полученное число перевести в четверичную систему счисления. Поэтому необходимо для каждой строки (i:=1,2,..,n) выполнить следующее: обнулить сумму S (S:=0), организовать цикл по элементам строки (j:=1,2,...,m), внутри которого проверять, является ли текущий элемент Ai,j простым, и если является, добавлять его к сумме S. После выхода из цикла по j необходимо проверить, были ли в строке с номером i простые числа (S>0), и если были, перевести S в четверичную систему счисления и сформировать соответствующий элемент массива P (P[i]:=perevod4(S)).

    (рис 6.27) Блок-схема алгоритма решения задачи 6.9

    Блок-схема алгоритма приведена на рис. 6.27.

    Полный текст консольного приложения приведён ниже.

    program pr_6_9;
    function prostoe (N: integer ) : boolean;
    var i : integer;
    	pr : boolean;
    begin
    if N<1 then pr := false
    else
    begin
    	pr := true;
    	for i :=2 to N div 2 do
    		if (N mod i = 0) then
    		begin
    			pr := false;
    			break;
    		end;
    end;
    prostoe := pr;
    end;
    function perevod4 (N: word ) : word;
    	var s1, q, ost : word;
    begin
    {В переменной s1 мы будем собирать число в четверичной системе}
    {счисления.}
    	s1 : = 0;
    {В переменной q будем последовательно хранить степени десяти, вначале}
    {туда записываем 1 - десять в 0 степени, а затем в цикле будем}
    {последовательно умножать q на 10.}
    q : = 1;
    {Перевод целого числа, пока число не станет равным 0.}
    		while (N<>0) do
    		begin
    {Вычисляем ost - очередной разряд числа, как остаток от деления N на 4}
    {(основание системы счисления).}
    		ost :=N mod 4;
    {Очередной разряд числа умножаем на 10 в степени i и добавляем к}
    {формируемому числу s1.}
    		s1 := s1+ost * q;
    {Уменьшаем число N в 4 раза путем целочисленного деления на 4.}
    		N:=N div 4;
    {Формируем следующую степень десятки.}
    		q:=q * 1 0;
    	end;
    //Возвращаем число в четверичной системе счисления.
    	perevod4 := s1;
    end;
    var S, i, j, n,m: word;
    	a : array [ 1.. 2 5, 1.. 2 5 ] of word;
    	p : array [ 1.. 2 5 ] of word;
    begin
    //Ввод размеров матрицы.
    	writeln ( ’Введите размеры матрицы ’ );
    	readln ( n,m);
    //Ввод матрицы.
    	writeln ( ’Введите матрицу A ’ );
    	for i :=1 to n do
    		for j :=1 to m do
    			read (A[ i, j ] );
    {Последовательно перебираем все строки матрицы для формирования суммы}
    {простых чисел каждой строки.}
    	for i :=1 to n do
    	begin
    //Вначале сумма равна нулю.
    		S : = 0;
    //Перебираем все элементы в i-й строке матрицы.
    		for j :=1 to m do
    //Если очередной элемент в i-й строке матрицы - простое число,
    //то добавляем его к сумме.
    			if prostoe (A[ i, j ] ) then s := s+A[ i, j ];
    {Если в строке были простые числа, то их сумму переводим в четверичную}
    {систему счисления и записываем в p[i].}
    			if s >0 then p [ i ] : = perevod4 ( s )
    {Если в строке не было простых чисел, то p[i]:=0.}
    		else p [ i ] : = 0;
    	end;
    //Вывод сформированного массива P.
    	writeln ( ’Массив P ’ );
    	for i :=1 to n do
    		write (P [ i ], ’   ’ );
    	writeln;
    end.
    

    Результаты работы программы представлены на рис. 6.28.

    (рис 6.28) Результаты работы программы решения задачи 6.9 ЗАДАЧА 6.10. Написать программу умножения двух матриц: $$A(N, M )$$ и $$B(M, L)$$.

    Напомним некоторые сведения из курса математики. Умножать можно только матрицы, у которых количество столбцов в первой матрице совпадает с количеством строк во второй матрице. Матрица-произведение имеет столько строк, сколько было в первой матрице и столько столбцов, сколько было во второй. Таким образом, при умножении матрицы A(N,M) на матрицу B(M,L) получается матрица C(N,L). Каждый элемент матрицы C[i,j] является скалярным произведением i-й строки матрицы A и j-го столбца матрицы B. В общем виде формула для нахождения элемента $$c_{i,j}$$ матрицы имеет вид:

    (рис 6.29) Блок-схема умножения двух матриц $$c_{i,j}=\sum\limits_{k=1}^{M}a_{ik}b_{kj},$$

    где $$i = 1,..., N$$ и $$j = 1,..., L$$.

    Рассмотрим более подробно формирование матрицы C(3,2) как произведения матриц A(3,3) и B(3,2).

    $$\left(\begin{matrix} c_{11}c_{12}\\ c_{21}c_{22}\\ c_{31}c_{32}\end{matrix}\right)= \left(\begin{matrix} a_{11}b_{11}+a_{12}b_{21}+a_{13}b_{31} a_{11}b_{12}+a_{12}b_{22}+a_{13} b_{32}\\ a_{21}b_{11}+a_{22}b_{21}+a_{23}b_{31} a_{21}b_{12}+a_{22}b_{22}+a_{23}b_{32}\\ a_{31}b_{11}+a_{32}b_{21}+a_{33}b_{31} a_{31}b_{12}+a_{32}b_{22}+a_{33}b_{32} \end{matrix}\right).$$

    Следует помнить, что $$A \cdot B \not = B \cdot A$$.

    Блок-схема, реализующая умножение каждого элемента матрицы C по формуле (6.1), приведена на рис. 6.29.

    Ниже приведён текст программы умножения двух матриц с комментариями.

    type
    	matrica=array [ 1.. 15, 1.. 15 ] of real;
    var
    	a, b, c : matrica;
    	i, j,M,N, L, k : byte;
    begin
    	//Ввод размеров матриц.
    	writeln ( ’введите n,m и  l ’ );
    	readln (N, M, L );
    //Ввод матрицы A.
    	writeln ( ’Матрица A ’ );
    	for i :=1 to N do
    		for j :=1 to M do
    			read ( a [ i, j ] );
    //Ввод матрицы B.
    	writeln ( ’Матрица B ’ );
    	for i :=1 to M do
    		for j :=1 to L do
    			read ( b [ i, j ] );
    //Формирование матрицы C.
    	for i :=1 to N do
    		for j :=1 to L do
    		begin
    {В C[i,j] будет храниться результат скалярного}
    {умножения i-й строки на j-й столбец.}
    			c [ i, j ] : = 0;
    			for k:=1 to M do
    				c [ i, j ] : = c [ i, j ]+a [ i, k ] * b [ k, j ];
    		end;
    //Вывод матрицы C=AB.
    	writeln ( ’матрица C=A*B ’ );
    	for i :=1 to N do
    	begin
    		for j :=1 to L do
    			write ( c [ i, j ] : 7 : 3, ’   ’ );
    		writeln;
    	end;
    end.
    

    Результат работы представлен на рис. 6.30.

    (рис 6.30) Результаты работы программы умножения двух матриц ЗАДАЧА 6.11. В матрице натуральных чисел $$A(N, M )$$ найти строки, в которых находится максимальное из простых чисел. Элементы в них упорядочить по возрастанию. Если в матрице нет простых чисел, то оставить её без изменений.

    Перед решением задачи отметим её некоторые особенности Авторы рекомендуют читателям внимательно изучить этот пример, в нём сконцентрированы практически все основные моменты, рассмотренные нами до сих пор. . В матрице может не быть простых чисел, максимальных значений может быть несколько, и при этом некоторые из них могут находиться в одной строке.

    При решении задачи нам понадобятся следующие подпрограммы:

  • Функция Prostoe, которая проверяет, является ли число P типа word простым. Она возвращает значение true, если число P — простое, и false — в противном случае. Заголовок функции имеет вид
    function Prostoe (P : word ) : Boolean;
    
  • Процедура Udal, которая из массива чисел X удаляет значения, встречающиеся более одного раза. У процедуры два параметра: массив X и его размер N, оба — параметры-переменные. Заголовок процедуры имеет вид:
    procedure Udal ( var X: massiv; var N: word );
    
    Перед описанием процедуры следует описать тип данных massiv (например, massiv = array [1..200] of word). Блок-схема процедуры Udal представлена на рис. 6.31. Удаление повторяющихся элементов происходит следующим образом. Просматриваются все элементы, начиная спервого, i-й элемент сравнивается со всеми последующими. Если, то встретился повторяющийся элемент, и мы удаляем из массива элемент с номером j. Алгоритм удаления был подробно рассмотрен в главе 5.
  • Функция Nalichie возвращает true, если число a присутствует в массиве b, и false — в противном случае. Заголовок процедуры имеет вид:
    function Nalichie ( a : word; b : massiv; N: word );
    
    Блок-схема функции представлена на рис. 6.32.
  • Процедура Vozr упорядочения массива х по возрастанию. Алгоритмы упорядочения рассматривались в главе 5. Здесь авторами использовался алгоритм сортировки методом пузырька. У процедуры Vozr два параметра: массив х (параметр-переменная) и его размер N (параметр-значение). Заголовок процедуры имеет вид:
    procedure Vozr ( var x : massiv; N: word );
    
  • (рис 6.31) Блок-схема процедуры Udal (рис 6.32) Блок-схема функции Nalichie

    Рассмотрим более подробно алгоритм решения задачи 6.11, который приведён на рис. 6.336.34.

    После ввода матрицы (блоки 1—4) предполагаем, что простых чисел нет. В логическую переменную Pr записываем false, как только встретится простое число, в переменную Pr запишем true. Количество максимальных значений среди простых чисел равно 0 (k:=0) (блок 5).

    Для проверки, является ли простым числом каждый элемент матрицы, обращаемся к функции Prostoe. Если число простое (блок 8), проверяем, первое ли это простое число в матрице (блок 9). Если это первое простое число, то переписываем его в переменную max, в переменную k записываем число 1 (количество максимумов равно 1), номер строки, в которой находится максимум, записываем в массив mas под номером k В массиве mas будут храниться номера строк, в которых находится максимум. . В связи с тем, что в матрице есть простые числа, в переменную Pr записываем true (блок 10). Если это не первое простое число, сравниваем A[i,j] с переменной max. Если A[i,j]>max (блок 11), то в переменную max запишем A[i,j], в переменную k запишем 1 (есть один максимум), в mas[k] записываем i — номер строки, где находится максимальный элемент (блок 12). Если A[i,j]=max (блок 13), то встретилось число, равное переменной max. В этом случае значение k увеличиваем на 1 и в mas[k] записываем номер строки, где находится элемент, равный max. В результате двойного цикла обработки всех элементов матрицы (блоки 6—14) в переменной max будет храниться максимальное из простых чисел, в переменной k — количество максимумов, в массиве mas из k элементов будут храниться номера строк, где находятся максимальные значение среди простых чисел матрицы. В переменной Pr хранится true, если в матрице есть простые числа, false — в противном случае. Если в матрице нет простых чисел (блок 15), выводим соответствующее сообщение (блок 16), в противном случае с помощью процедуры Udal (блок 17) удаляем из массива mas элементы, встречающиеся более одного раза Если некоторые максимальные элементы находятся в одной строке, то в массиве mas есть повторяющиеся элементы. . Затем просматриваем все строки матрицы (цикл начинается блоком 18). Если номер этой строки присутствует в массиве mas (блок 19), то переписываем текущую строку матрицы в массив b (блоки 20—21) и обращаемся к процедуре упорядочения массива по возрастанию Vozr (блок 22). Упорядоченный массив b переписываем в i-ю строку матрицы А (блоки 23—24). На последнем этапе выводим на экран матрицу А после преобразования (блоки 25—27).

    (рис 6.33) Блок-схема решения задачи 6.11 (начало) (рис 6.34) Блок-схема решение задачи 6.11 (продолжение)

    Ниже приведён листинг всей программы с подробными комментариями.

    {Тип данных massiv будет использоваться при описании процедур.}
    type
    massiv=array [ 1.. 200 ] of word;
    {Функция prostoe проверяет, является ли число N простым (true) или нет}
    {(false).}
    function prostoe (N: word ) : boolean;
    var pr : boolean; i : word;
    begin
    	if N>0 then
    	begin
    {Предполагаем, что число N - простое (pr=true).}
    		pr := true;
    {Проверяем, делится ли число N на какое либо из чисел от 2 до N/2.}
    		for i :=2 to n div 2 do
    {Если встречается число i, на которое делится N, то}
    		if N mod i =0 then
    		begin
    {число N не является простым (pr=false) и}
    			pr := false;
    {выходим из цикла.}
    			break;
    		end
    	end
    	else pr := false;
    {Имени функции присваиваем значение переменной pr.}
    	prostoe := pr;
    end;
    {Процедура udal удаляет из массива x элементы, которые встречаются}
    {более одного раза. Х, N являются параметрами-переменными, так как эти}
    {значения возвращаются в головную программу при вызове процедуры udal.}
    procedure udal ( var x : massiv; var n : word );
    var i, j,m: word;
    begin
    	i : = 1;
    {Просматриваем все элементы, начиная с первого i=1,2,...,N;i-й элемент}
    {сравниваем с последующими j=i+1,i+2,...,n.}
    	while ( i<=n ) do
    	begin
    		j := i +1;
    		while ( j<=N) do
    {Если x[i] равно x[j], то встретился повторяющийся элемент -}
    		if x [ i ]=x [ j ] then
    		begin
    {удаляем его (x[j]) из массива.}
    			for m:= j to N _1 do
    			x [m] : = x [m+ 1 ];
    {После удаления элемента количество элементов уменьшаем на 1, при этом}
    {не переходим к следующему элементу, так как после удаления под j-м}
    {номером находится уже другой элемент.}
    			N:=N-1;
    		End
    {Если x[i] не равно x[j], то переходим к следующему элементу.}
    		else j := j +1;
    		i := i +1;
    	end;
    end;
    {Функция nalichie возвращает true, если число a встречается в массиве}
    {b, false - в противном случае.}
    function nalichie ( a : word; b : massiv; n : word ) : boolean;
    var
    	pr : boolean;
    	i : word;
    begin
    {Предполагаем, что в массиве b не встречается значение a - pr=false}
    	pr := false;
    {Перебираем все элементы массива.}
    	for i :=1 to N do
    {Если очередной элемент массива b равен значению a, то в pr записываем}
    {true}
    	if b [ i ]=a then
    		begin
    		pr := true;
    {и выходим из цикла.}
    		break
    	end;
    {Имени функции присваиваем значение переменной pr.}
    	nalichie := pr
    end;
    {Процедура vozr упорядочивает массив x по возрастанию.}
    procedure vozr ( var x : massiv; n : word );
    {X является параметром-переменной, именно массив и возвращается в}
    {головную программу при вызове процедуры vozr.}
    var i, j, b : word;
    begin
    	for i :=1 to N -1 do
    		for j :=1 to N -i do
    			if x [ j ]>x [ j +1] then
    			begin
    				b:=x [ j ];
    				x [ j ] : = x [ j + 1 ];
    				x [ j +1]:=b;
    			end
    	end;
    //Начинается основная программа.
    var
    	N, M, i, j, k, max : word;
    	A: array [ 1.. 20, 1.. 20 ] of word;
    	pr, L : boolean;
    	mas, b : massiv;
    begin
    {Вводим элементы матрицы А.}
    	write ( ’N= ’ ); readln (N);
    	write ( ’M= ’ ); readln (M);
    writeln ( ’   Matrica  A ’ );
    	for i :=1 to N do
    	for j :=1 to M do
    		read (A[ i, j ] );
    {Предполагаем, что в матрице нет простых чисел.}
    	Pr:= false;
    {Количество элементов, равных максимальному, равно 0.}
    	k : = 0;
    {Перебираем все элементы в матрице.}
    	for i :=1 to N do
    	for j :=1 to M do
    	begin
    {Обращаемся к функции, которая проверяет, является ли число A[i,j]}
    {простым.}
    		L:= Prostoe (A[ i, j ] );
    {Если число простое, и}
    		if L then
    {если простое число встретилось первый раз,}
    		if not Pr then
    		begin
    {записывем в pr true,}
    			Pr:= true;
    {увеличиваем количество максимумов на 1, можно было просто написать}
    {k:=1.}
    			k:=k+1;
    {Это число записываем в переменную max. Это первое простое число, и}
    {предполагаем, что оно максимальное.}
    			max:=A[ i, j ];
    {В mas[k] записываем номер строки, где хранится число A[i,j].}
    			mas [ k ] : = i
    		end
    	else
    {Если A[i,j] - не первое простое число, то сравниваем max и текущее}
    {простое значение матрицы А.}
    		if A[ i, j ]>max then
    {Если A[I,j]> max, то}
    		begin
    {количество максимумов равно 1, т. к. встретился наибольший в данный}
    {момент элемент.}
    			k : = 1;
    {В переменную max записываем A[i,j],}
    			max:=A[ i, j ];
    {в mas[k] записываем номер строки, где хранится число A[i,j]}
    			mas [ k ] : = i
    		end
    	else
    {Если A[i,j]=max (встретился элемент, равный максимуму), то}
    if A[ i, j ]=max then
    			begin
    {количество максимумов увеличиваем на 1,}
    				k:=k+1;
    {в mas[k] записываем номер строки, где хранится число A[i,j].}
    				mas [ k ] : = i
    			end
    	end;
    {Если в pr осталось значение false,то выводим сообщение, что в матрице}
    {нет простых чисел,}
    	if not Pr then writeln ( ’В матрице A нет простых чисел ’ )
    	else
    	begin
    {иначе удаляем из массива mas номера строк, где хранятся максимумы,}
    {повторяющиеся элементы.}
    		Udal ( mas, k );
    {Перебираем все строки матрицы.}
    		for i :=1 to N do
    		begin
    			L:= Nalichie ( i, mas, k );
    {Если номер строки присутствует в массиве mas,}
    			if L then
    			begin
    {то переписываем строку в массив b,}
    				for j :=1 to M do
    				b [ j ] : =A[ i, j ];
    {упорядочиваем массив b по возрастанию.}
    				Vozr ( b,M);
    {Упорядоченный массив записываем на место i-й строки матрицы A.}
    				for j :=1 to M do
    				A[ i, j ] : = b [ j ];
    			end
    		end;
    	writeln ( ’Преобразованная матрица A ’ );
    	for i :=1 to N do
    	begin
    		for j :=1 to M do
    		write (A[ i, j ], ’   ’ );
    		writeln;
    		end
    	end
    end.
    

    Результаты работы программы приведены на рис. 6.35.

    (рис 6.35) Результаты решения задачи 6.11

    Авторы рекомендуют читателю по рассмотренным алгоритмам и консольным приложениям задач 6.7—6.11 разработать визуальные приложения, аналогичные тем, которые были разработаны для задач 6.2 и 6.6.

    В завершении этой главы рассмотрим "динамические матрицы".

    6.3 Динамические матрицы

    Понятие динамического массива можно распространить и на матрицы. Динамическая матрица представляет собой массив указателей, каждый из которых адресует одну строку (или один столбец).

    Рассмотрим описание динамической матрицы. Пусть есть типы данных massiv и указатель на него din_massiv.

    type massiv=array [ 1.. 1000 ] of real;

    din_massiv=^massiv;

    Динамическая матрица X будет представлять собой массив указателей.

    var X: array [ 1.. 100 ] of din_massiv;

    Работать с матрицей надо следующим образом:

  • Определить её размеры (пусть N — число строк, M — число столбцов).
  • Выделить память под матрицу.
  • for i :=1 to N do

    getmem(X[ i ],M * sizeof ( real ) );

    Каждый элемент статического массива X[i] — указатель на динамический массив, состоящий из M элементов типа real. В статическом массиве Х находится N указателей.

  • Для обращения к элементу динамической матрицы, расположенному в i-й строке и j-м столбце, следует использовать конструкцию языка Турбо Паскаль X[i]^[j].
  • После завершения работы с матрицей необходимо освободить память.
  • for i :=1 to N do

    freemem ( b [ i ],M * sizeof ( real ) );

    Рассмотрим работу с динамической матрицей на следующем примере.

    ЗАДАЧА 6.12. В каждой строке матрицы вещественных чисел B(N, M ) упорядочить по возрастанию элементы, расположенные между максимальным и минимальным значениями.

    Алгоритмы упорядочения рассматривались в главе 5, основные принципы работы с матрицами — в предыдущих параграфах текущей главы, поэтому в комментариях к тексту программы основное внимание уделено особенностям работы с динамическими матрицами.

    {Описываем тип данных massiv как массив 1000 вещественных чисел.}
    type massiv=array [ 1.. 1000 ] of real;
    {Указатель на массив.}
    din_massiv=^massiv;
    {Тип данных matrica - статический массив указателей, каждый элемент}
    {которого является адресом массива вещественных чисел.}
    matrica=array [ 1.. 100 ] of din_massiv;
    var
    Nmax, Nmin, i, j, n,m, k : word;
    {Описана динамическая матрица b.}
    b : matrica;
    a, max, min : real;
    begin
    {Вводим число строк N и число столбцов M.}
    write ( ’N= ’ ); readln (N);
    write ( ’M= ’ ); readln (M);
    {Выделяем память под матрицу вещественных чисел размером N на M.}
    for i :=1 to N do
    getmem( b [ i ],M * sizeof ( real ) );
    { Вводим Матрицу B. }
    writeln ( ’ Matrica B ’ );
    for i :=1 to N do
    for j :=1 to M do
    read ( b [ i ] ^ [ j ] );
    {В каждой строке находим максимальный, минимальный элементы и их номера}
    {и элементы, расположенные между ними, упорядочиваем "методом}
    {пузырька".}
    for i :=1 to N do
    begin
    {Поиск минимального, максимального элемента в i-й строке матрицы и их}
    {номеров.}
    max:=b [ i ] ^ [ 1 ];
    Nmax: = 1;
    min:=b [ i ] ^ [ 1 ];
    Nmin : = 1;
    for j :=2 to M do
    begin
    if b [ i ] ^ [ j ]>max then
    begin
    max:=b [ i ] ^ [ j ];
    nmax:= j
    end;
    if b [ i ] ^ [ j ]<min then
    begin
    min:=b [ i ] ^ [ j ];
    nmin:= j
    end;
    end;
    {Если минимальный элемент расположен позже максимального, nmin и nmax}
    {меняем местами.}
    if nmax<nmin then
    begin
    j :=nmax;
    nmax:=nmin;
    nmin:= j;
    end;
    {В i-той строке упорядочиваем элементы, расположенные между nmin и}
    {nmax, "методом пузырька".}
    j : = 1;
    while nmax-1 - j>=nmin+1 do
    begin
    for k:=nmin+1 to nmax-1 - j do
    if b [ i ] ^ [ k]>b [ i ] ^ [ k+1] then
    begin
    a:=b [ i ] ^ [ k ];
    b [ i ] ^ [ k ] : = b [ i ] ^ [ k + 1 ];
    b [ i ] ^ [ k+1]:= a;
    end;
    j := j +1;
    end;
    end;
    { Выводим преобразованную матрицу. }
    writeln ( ’Упорядоченная матрица B ’ );
    for i :=1 to N do
    begin
    for j :=1 to M do
    write ( b [ i ] ^ [ j ] : 6 : 2, ’   ’ );
    writeln
    end;
    { Освобождаем память. }
    for i :=1 to N do
    freemem ( b [ i ],M * sizeof ( real ) );
    end.
    

    Результаты работы программы представлены на рис. 6.36.

    Динамическая матрица может быть достаточно большой, фактически её размер ограничен только объемом свободной памяти.

    В заключении главы приведём задачи для самостоятельного решения.

    (рис 6.36) Результаты решения задачи 6.12
    Вернуться к учебному плану