Найти обратную матрицу (Pascal)

Найти обратную матрицу (Pascal)

Вообщем задача состоит в том, что надо найти обратную матрицу, по следующему алгоритму: 1. Разбиваем матрицу на 2 треугольные 2. Находим обратные матрицы к треугольным и перемножаем их (должны получить обратную матрицу к той что нам дана) 3. Проверка.

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

13 ответов

Не помню что такое "с алгебраическими дополнениями", но припоминается что можно привести ее к треугольному виду (ето не то что разбить на 2 треугольние, а так чтоб все что под диагоналю было равно 0), а потом перемножыть елементы диагонали.

ЗЫ. ИМХО. А прежний аватар красивее был.

когда я тестирую, вроде все нормально, но когда матрица 2х2 (порядок равен 2), то определитель что-то не считается:confused: не могу найти ошибку, помогите пожалуйста.

(Может не совсем будет роботать потому что я прямо тут и набрал с копипейстом.)

Твоя ошибка в том что после первого ифа надо было остальное в елсе взять. Но ето машинально. А теперь концептуально. Видиш, у тебя вычисление для н=2 делается два раза (в ифе и после цыкла). Старайся избегать таких ситуаций.

Извени, но помойму я тебе не так подсказал сам метод. Я тут на бумажке пробую и не получается у меня так посчитать. Пошел учить матчасть.

PS Ето у меня руки кривые на бумажке считать, таки правильно сказал. Ложная тривога. Завтра покажу как без вспомагательной mat11 обойтись. Сегодня не успеваю.

type Tmatr = array[1..NMAX, 1..NMAX] of real;

const mat: Tmatr = ((8, 4, 9, 2), (3, 7, 4, 5), (3, 6, 9, 8), (1, 1, 4, 1));

var mat1: Tmatr; n, i, j, k, current: integer; det, buf: real;

BEGIN mat1 := mat; n := 4; det:=1; current := 1; while(n > current) do begin if mat1[current, current]=0 then begin k:=0; for i:=current to n do if mat1[i,current] <> 0 then k:=i; if k=0 then begin det:=0; break; end; for j:=current to n do begin buf:=mat1[current,j]; mat1[current,j]:=mat1[k,j]; mat1[k,j]:=buf; end; det:=(-1)*det; end; for i:=current+1 to n do begin buf := mat1[i, current] / mat1[current, current]; for j:=current to n do mat1[i,j]:=mat1[i,j]-buf*mat1[current,j]; end; current := current + 1; end; for i := 1 to n do det := det * mat1[i,i]; for i := 1 to n do begin for j := 1 to n do write(mat1[i,j]:10:3, ', '); writeln; end; writeln('det=',det:8:3); end.

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

Замечание тебе 1.

Условие лутше ставить перед обменом местами строк. Кроме того при к=0 нужно прекращать приведение матрицы, а тто потом сразу деление на 0 вылезет.

2. В паскале можно переприсвоить масив полностю, а не поелементно. Но для етого надо чтоб они были одного типа. Тоесть примерно так.

type Tmatr = array[1..NMAX, 1..NMAX] of real;

const mat: Tmatr = ((8, 4, 9, 2), (3, 7, 4, 5), (3, 6, 9, 8), (1, 1, 4, 1));

3. Не обязательно роботать через елемент [1,1]. Сделaл через current. Так у тебя остается неиспорченая матрица. (Выводится в конце).

4. Можно убрать вспомагательную матрицу и делать все на одной.

5. Убрал проверку на розмер матрицы ровный 2. Ето конечно лишняя итерацыя цыкла, но мое мнение что надо стараться делать код более универсальным. Тоесть чтоб он обрабатывал любые входные данные одинаково. Так снижается вероятность ошибок. В етом ты уже сам убедился. :)

6. Основное замечание. Индексируй масивы с нуля. Ето секономит тебе кучу времени и нервов когда начнеш писать на Си подобных языках.

Надеюсь мой код будет тебе полезным.

procedure output_matrix(n:integer;mat:mat1); var i,j:integer; begin for i:=1 to n do begin for j:=1 to n do begin write(mat[i,j]:5:5); write(' '); end; writeln; end; writeln; end;

procedure bermuda(var nt,vt,d:mat1; n:integer); var i,j,k:integer; s:real; begin for i:=1 to n do begin nt[i,1]:=d[i,1]; vt[i,1]:=0; end; for j:=1 to n do begin vt[1,j]:=d[1,j]/nt[1,1]; if j>1 then nt[1,j]:=0; end; for i:=2 to n do for j:=2 to n do begin if i>=j then begin s:=0; for k:=1 to j-1 do s:=s+nt[i,k]*vt[k,j]; nt[i,j]:=d[i,j]-s; vt[i,j]:=0; if i=j then vt[i,j]:=1; end else begin s:=0; for k:=1 to i-1 do s:=s+nt[i,k]*vt[k,j]; vt[i,j]:=(d[i,j]-s)/nt[i,i]; nt[i,j]:=0; end; end; end;

procedure ont(n:integer; var mat,obnt:mat1); var i,j,a:integer; s:real; begin for i:=1 to n do begin for j:=1 to n do begin if i=j then obnt[i,j]:=1/mat[i,j]; if i<j then obnt[i,j]:=0; if i>j then begin s:=0; for a:=j to i-1 do begin s:=s+mat[i,a]*obnt[a,j]; obnt[i,j]:=-1*s/mat[i,i]; end; end; end; end; end;

procedure ovt(n:integer; var mat,obvt:mat1); var i,j,a:integer; s:real; begin for i:=n downto 1 do begin for j:=1 to n do begin if i>=j then obvt[i,j]:=mat[i,j]; if j=i+1 then obvt[i,j]:=-mat[i,j]; if j>i+1 then begin s:=0; for a:=i+1 to j-1 do begin s:=s+mat[i,a]*obvt[a,j]; obvt[i,j]:=-1*(mat[i,j]+s); end; end; end; end; end;

procedure multi_matrix(n:integer; m1,m2:mat1; var mm:mat1); var i,j,a:integer; x:real; begin for i:=1 to n do for j:=1 to n do begin x:=0; for a:=1 to n do x:=x+m1[i,a]*m2[a,j]; mm[i,j]:=x; end; end; end.

Конечно код не маленький, но кому не трудно просмотрите пожалуйста. При тестировании он для всех матриц работает нормально, кроме тех в которых самый первый элемент (т.е. с индексом [1,1]) равен нулю, для них не считает:( Пытаюсь найти сам, но что-то не получается (это как с русским языком, свои ошибки сразу не находишь, надо отвлечся, а на сежий глаз легче увидеть, особенно если она какая-нить глупая)

📎📎📎📎📎📎📎📎📎📎