Pers.narod.ru. Алгоритмы. Решение СЛАУ методом Гаусса |
Наиболее известным и популярным точным способом решения систем линейных алгебраических уравнений (СЛАУ) является метод Гаусса. Этот метод заключается в последовательном исключении неизвестных. Пусть в системе уравнений
первый элемент a11(0) не равен 0. Назовем его ведущим элементом первой строки. Поделим все элементы этой строки на a11(0) и исключим x1 из всех последующих строк, начиная со второй, путем вычитания первой (преобразованной), умноженной на коэффициент при x1 в соответствующей строке. Получим
Если a22(1), то, продолжая аналогичное исключение, приходим к системе уравнений с верхней треугольной матрицей
Из нее в обратном порядке находим все значения xi:
Процесс приведения к системе с треугольной матрицей называется прямым ходом, а нахождения неизвестных - обратным. Если один из ведущих элементов равен нулю, изложенный алгоритм метода Гаусса неприменим. Тем не менее, для нормальной матрицы с ненулевым определителем всегда возможна такая перестановка уравнений, что на главной диагонали не будет нулей. В приведенном коде для простоты перестановок не делается, зато делается проверка решения, а прямой и обратный ход для наглядности вынесены в отдельные подпрограммы.
{ Написать программу решения СЛАУ Ax=b методом Гаусса. } program SLAU; const size=30; type matrix=array [1..size,1..size] of real; type vector=array [1..size] of real; procedure GetDimension (var n:integer; s:string); begin repeat writeln (s); readln (n); if (n<2) or (n>size) then writeln ('Должно быть число от 2 до ', size); until (n>1) and (n<size); end; procedure GetMatrix (n,m:integer; var a:matrix); var i,j:integer; begin for i:=1 to n do begin writeln ('Строка ',i); for j:=1 to m do read (a[i,j]); end; end; procedure PutMatrix (n,m:integer; var a:matrix); var i,j:integer; begin for i:=1 to n do begin writeln; for j:=1 to m do write (a[i,j]:10:3); end; end; procedure GetVector (n:integer; var a:vector); var i:integer; begin for i:=1 to n do begin write (i,' элемент='); readln (a[i]); end; end; procedure PutVector (n:integer; var a:vector); var i:integer; begin writeln; for i:=1 to n do writeln (a[i]:10:3); end; procedure DirectGauss (n:integer; var a:matrix; var b:vector); var i,j,k:integer; buf:real; begin for i:=1 to n-1 do for j:=i+1 to n do begin buf:=a[i,i]/a[j,i]; for k:=1 to n do a[j,k]:=a[j,k]*buf-a[i,k]; b[j]:=b[j]*buf-b[i]; end; end; procedure ObratGauss (n:integer; var a:matrix; var x,b:vector); var i,j,k:integer; buf:real; begin x[n]:=b[n]/a[n,n]; for i:=n-1 downto 1 do begin buf:=0; for j:=i+1 to n do buf:=buf+a[i,j]*x[j]; x[i]:=(b[i]-buf)/a[i,i]; end; end; procedure Mvmul (n,m:integer; var a:matrix; var x,b:vector); var i,j:integer; begin for i:=1 to n do begin b[i]:=0; for j:=1 to m do b[i]:=b[i]+a[i,j]*x[j]; end; end; var a,a2:matrix; x,b:vector; n,m:integer; begin GetDimension (n,'Введите размерность квадратной матрицы'); m:=n; GetMatrix (n,m,a); a2:=a; writeln ('Ввод правой части:'); GetVector (n,b); DirectGauss (n,a,b); ObratGauss (n,a,x,b); write ('Решение:'); PutVector (m,x); write ('Проверка A*x:'); Mvmul (n,m,A2,x,b); PutVector (n,b); Reset (Input); Readln; end.
Аналогичная программа на C++ выглядит следующим образом:
/* Написать программу для решения системы линейных алгебраческих уравнений (СЛАУ) методом Гаусса */ #include <iostream.h> #include <conio.h> #include <stdlib.h> void main () { const int n=3; //Размерность системы float a[n][n+1],a0[n][n+1]; //A - расширенная матрица системы, A0 - ее копия для проверки решения int i,j,k; float buf,x[n],b[n]; clrscr(); randomize (); cout << "Матрица и вектор правой части"; for (i=0; i<n; i++) { cout << endl; for (j=0; j<n+1; j++) { a0[i][j]=a[i][j]=1+random(100)/25.; //Нулевых элементов нет, деления на ноль не будет cout << a[i][j] << " "; } } //Прямой ход метода Гаусса for (i=0;i<n-1;i++) for (j=i+1;j<n;j++) { buf=a[i][i]/a[j][i]; for (k=0;k<=n;k++) a[j][k]=a[j][k]*buf-a[i][k]; } //Обратный ход метода Гаусса x[n-1]=a[n-1][n]/a[n-1][n-1]; for (i=n-2;i>=0;i--) { buf=0; for (j=i+1;j<n;j++) buf+=a[i][j]*x[j]; x[i]=(a[i][n]-buf)/a[i][i]; } cout << endl << "Решение" << endl; for (i=0; i<n; i++) cout << x[i] << " "; cout << endl << "Проверка" << endl; for (i=0; i<n; i++) { b[i]=0; for (j=0; j<n; j++) b[i]+=a0[i][j]*x[j]; cout << b[i] << " "; } }
Здесь матрица и вектор правой части генерируются случайным образом из чисел в диапазоне от 1 до 5:
1+random(100)/25.
Естественно, диапазон можно поменять.
Лучшее решение на Паскале есть вот здесь.
гостевая; E-mail |