Алгоритм метода Гаусса с выбором главного элемента по столбцам.

1. Для m = 1, 2, …, n – 1 выполним преобразования:

Найдем максимальный по абсолютной величине элемент в m-ом столбце. Пусть это будет элемент aim. Если im, то меняем местами i-ую и m-ую строки:

 

r = aij, aij = amj, amj = r, j = 1, …, n; r = bi, bi = bm, bm = r.

 

Элементы матрицы и вектора после преобразования на m-ом шаге обозначим , причем .

Делим m-ое уравнение на ведущий элемент :

 

 

а затем исключаем переменную xm с помощью m-ого уравнения из i-го,
где i = m + 1, …, n:

 

 

2. Вычисляем неизвестные xi в обратном порядке:

 

;

 

Приведенный вариант метода Гаусса дает решение и тогда, когда обычный метод Гаусса перестает работать из-за деления на ноль.

При реализации метода Гаусса на каком-либо языке программирования удобно использовать исходные матрицу a и вектор b для хранения промежуточных результатов преобразований. Приведенные формулы преобразований записываются как операторы присваивания, т.е. имена переменных aij и bj записываются без верхних индексов. Ниже приведены различные примеры программ метода Гаусса.

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

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

Мы не будем рассматривать реализации указанных вариантов метода Гаусса. Отметим, что последний вариант метода Гаусса с выбором главного элемента считается лучшим.

Общее число операций для решения системы уравнений методом Гаусса составляет приблизительно [1] 2n3/3 + 2n2, при этом большая часть, т.е. 2n3/3 операций приходится на прямой ход.

Пример 3.3. Решить методом Гаусса систему уравнений

4x1 + 2x2 – 4x3 + 2x4 = 12,

2x1 + 9x2 – 4x3 – 4x4 = 14,

3x1 + 2x2 – 8x3 + 2x4 = 20,

4x1 + 2x2 + 5x3 + 7x4 = 10.

Решение.Продемонстрируем решение в программе электронных таблиц.

0. Запишем коэффициенты и правые части системы в диапазоне A1:E4.

1. В диапазоне A5:E8 сформируем расширенную матрицу системы, которая получится после исключения переменной x1 из второго, третьего и четвертого уравнений.

В ячейку A5 вводим формулу =A1/$A1; выделим A5 и протянем маркер заполнения (мышью за правый нижний угол) до E5.

Затем в ячейку A6 вводим формулу =A2-A$5*$A2; выделим A6 и протянем маркер заполнения до E6.

Выделим диапазон A6:E6 и протянем маркером заполнения до E8.

В ячейках A5:E8 появятся следующие значения:

1,0000 0,5000 -1,0000 0,5000 3,0000
0,0000 8,0000 -2,0000 -5,0000 8,0000
0,0000 0,5000 -5,0000 0,5000 11,0000
0,0000 0,0000 9,0000 5,0000 -2,0000

 

2. В диапазоне A9:E12 сформируем матрицу системы, которая получится после исключения x2 из третьего и четвертого уравнений.

Присвоим строке A9:E9 значения строки A5:E5, т.е. выделим диапазон A9:E9 и введем формулу =A5:E5 и удерживая нажатыми клавиши Ctrl и Shift, нажимаем Enter.

В ячейку B10 вводим формулу =B6/$B6; выделим B10 и протянем маркер заполнения до E10.

Затем в ячейку B11 вводим формулу =B7-B$10*$B7; выделим B11 и протянем мышью маркер заполнения до E11.

Выделим диапазон B11:E11 и протянем маркер заполнения до E12.

В ячейках A9:E12 появятся следующие значения:

 

1,0000 0,5000 -1,0000 0,5000 3,0000
0,0000 1,0000 -0,2500 -0,6250 1,0000
  0,0000 -4,8750 0,8125 10,5000
  0,0000 9,0000 5,0000 -2,0000

 

3. В диапазоне A13:E16 сформируем матрицу системы, которая получится после исключения x3 из четвертого уравнения.

Перепишем значения строк A9:E10 в строки A13:E14, для этого выделим диапазон A13:E14 и введем формулу =A9:E10 и удерживая клавиши Ctrl и Shift нажатыми, нажимаем Enter.

В ячейку C15 вводим формулу =C11/$C11; выделим C15 и протянем мышью за правый нижний угол до E15.

В ячейку C16 вводим формулу =C12-C$15*$C12, выделим C16 и протянем мышью за правый нижний угол до E16. В ячейках A13:E16 получим значения:

 

1,0000 0,5000 -1,0000 0,5000 3,0000
0,0000 1,0000 -0,2500 -0,6250 1,0000
    1,0000 -0,1667 -2,1538
    0,0000 6,5000 17,3846

 

4. Сформируем в диапазоне A17:E20 окончательную матрицу системы, которая имеет треугольный вид с единицами на диагонали.

Выделим диапазон A17:E19 и введем формулу =A13:E15 и, удерживая нажатыми клавиши Ctrl и Shift, нажимаем Enter. В ячейку D20 вводим формулу =D16/$D16, выделим C15 и протянем мышью за правый нижний угол до E20. В диапазоне A17:E20 получим:

1,0000 0,5000 -1,0000 0,5000 3,0000
0,0000 1,0000 -0,2500 -0,6250 1,0000
0,0000 0,0000 1,0000 -0,1667 -2,1538
      1,0000 2,6746

 

В таблице 3.1 показаны введенные формулы, которые можно увидеть, если выполнить команду меню «Сервис — параметры», выбрать вкладку «Вид» и отметить в параметрах окна флажком пункт «формулы».

5. Теперь остается выполнить обратный ход метода Гаусса. Для этого в ячейках F17:F20 введем формулы:

 

=E17-F20*D17-F19*C17-F18*B17
=E18-F20*D18-F19*C18
=E19-F20*D19
=E20

 

В ячейках F17:F20 получим ответ:

x1 = –1,1677; x2 = 2,2446; x3 = –1,7081; x2 =2,6746.

 

Таблица 3.1

  A B C D E
-4
-4 -4
-8
=A1/$A1 =B1/$A1 =C1/$A1 =D1/$A1 =E1/$A1
=A2-A$5*$A2 =B2-B$5*$A2 =C2-C$5*$A2 =D2-D$5*$A2 =E2-E$5*$A2
=A3-A$5*$A3 =B3-B$5*$A3 =C3-C$5*$A3 =D3-D$5*$A3 =E3-E$5*$A3
=A4-A$5*$A4 =B4-B$5*$A4 =C4-C$5*$A4 =D4-D$5*$A4 =E4-E$5*$A4
=A5:E5 =A5:E5 =A5:E5 =A5:E5 =A5:E5
=B6/$B6 =C6/$B6 =D6/$B6 =E6/$B6
  =B7-B$10*$B7 =C7-C$10*$B7 =D7-D$10*$B7 =E7-E$10*$B7
  =B8-B$10*$B8 =C8-C$10*$B8 =D8-D$10*$B8 =E8-E$10*$B8
=A9:E10 =A9:E10 =A9:E10 =A9:E10 =A9:E10
=A9:E10 =A9:E10 =A9:E10 =A9:E10 =A9:E10
    =C11/$C11 =D11/$C11 =E11/$C11
    =C12-C$15*$C12 =D12-D$15*$C12 =E12-E$15*$C12
=A13:E15 =A13:E15 =A13:E15 =A13:E15 =A13:E15
=A13:E15 =A13:E15 =A13:E15 =A13:E15 =A13:E15
=A13:E15 =A13:E15 =A13:E15 =A13:E15 =A13:E15
      =D16/$D16 =E16/$D16

 

В таблице 3.2 приведены результаты решения системы (после снятия флажка с пункта «формулы» меню «Сервис — параметры»).

Таблица 3.2

  A B C D E F
-4 12,0000
-4 -4 14,0000
-8 20,0000
10,0000
1,0000 0,5000 -1,0000 0,5000 3,0000  
0,0000 8,0000 -2,0000 -5,0000 8,0000  
0,0000 0,5000 -5,0000 0,5000 11,0000  
0,0000 0,0000 9,0000 5,0000 -2,0000  
1,0000 0,5000 -1,0000 0,5000 3,0000  
0,0000 1,0000 -0,2500 -0,6250 1,0000  
  0,0000 -4,8750 0,8125 10,5000  
  0,0000 9,0000 5,0000 -2,0000  
1,0000 0,5000 -1,0000 0,5000 3,0000  
0,0000 1,0000 -0,2500 -0,6250 1,0000  
    1,0000 -0,1667 -2,1538  
    0,0000 6,5000 17,3846  
1,0000 0,5000 -1,0000 0,5000 3,0000 -1,1677
0,0000 1,0000 -0,2500 -0,6250 1,0000 2,2446
0,0000 0,0000 1,0000 -0,1667 -2,1538 -1,7081
      1,0000 2,6746 2,6746

 

6. Для проверки правильности введенных формул умножим исходную матрицу коэффициентов, хранящихся в ячейках A1:D4, на столбец найденных решений F17:F20, и запишем полученные значения в столбец F1:F4.

Для этого выделим диапазон F1:F4, введем формулу

=МУМНОЖ(A1:D4;F17:F20)

и, удерживая нажатыми клавиши Ctrl и Shift, нажмем Enter. Значения в столбцах E1:E4 и F1:F4 должны совпадать.

Замечание.Приведенный лист с формулами можно применить для решения любой системы уравнений с четырьмя неизвестными. Для этого в диапазоне A1:E4 введем коэффициенты и правые части новой системы уравнений. В диапазоне F17:F20 автоматически отобразится решение новой системы уравнений.

Проверить правильность алгоритма можно, например, заменив числа в столбце E1:E4 суммами коэффициентов уравнений. Тогда вектор решений должен состоять из единиц.

Приведем программу на языке C++ для решения системы линейных уравнений методом Гаусса с выбором главного элемента:

 

#include <except.h>

#include <iostream.h>

int gauss(long double **a, long double *b, long double *x, const int n);

int main(){

long double **a; long double *b; long double *x; int i,j,n;

cout <<" input n = " ; cin >> n;

try {

a= new long double*[n]; for(i=0;i<n;i++) a[i]=new long double[n];

b= new long double[n]; x= new long double[n];

}

catch (xalloc){cout <<" Could not allocate "; exit(-1);}

cout <<" input matrix a ";

for (i=0; i<n; i++)for (j=0; j<n; j++)cin >> a[i][j];

cout <<" input vector b ";

for (i=0; i<n; i++)cin >> b[i];

cout << " matrix a: ";

for (i=0; i<n; i++){cout << " "; for (j=0; j<n; j++) cout <<" "<< a[i][j];}

cout << " vector b: ";

for (i=0; i<n; i++)cout << " " << b[i];

gauss(a, b, x, n);

cout << " vector x: ";

for (i=0; i<n; i++)cout << " x[" << i <<"] = " << x[i];

cout << " Press Key and Enter to continue";

cin >> i; // for pause

for(i=0;i<n;i++)delete[] a[i];

delete a;

delete[] b;

delete[] x;

return 0;

}//end main

int gauss(long double **a, long double *b, long double *x, const int n){

// Метод Гаусса с выбором главного элемента

int i, k, m, im; long double amm, aim, r;

for (m = 0; m <= n-2; m++) {// m

amm = a[m][m]; im = m;

for (i = m; i <= n-1; i++)

if(a[i][m] > amm){amm = a[i][m]; im = i; }

if(im != m){r = b[im]; b[im] = b[m]; b[m] = r;

for (k = m; k <= n-1; k++)

{r = a[im][k]; a[im][k] = a[m][k]; a[m][k] = r;}

}

for (k = m; k <= n-1; k++)a[m][k] = a[m][k]/amm; // 3.16

b[m] = b[m] / amm; //

for (i = m + 1; i <= n-1; i++){// i

aim = a[i][m];

for (k = m; k <= n-1; k++)

a[i][k] = a[i][k] - a[m][k]*aim; // 3.17

b[i] = b[i] - b[m]*aim; //

}// end i

}// end m

x[n-1] = b[n-1]/a[n-1][n-1]; // 3.19

for (i = n - 2; i >= 0; i--){// i

x[i] = b[i]; //

for (k = i + 1; k < n; k++) // 3.20

x[i] = x[i] - a[i][k]*x[k]; //

}// end i

return 0;

}// end gauss

 

Приведем для сравнения вариант процедуры обычного метода Гаусса:

 

int gauss(long double **a, long double *b, long double *x, const int n){

// Метод Гаусса

int i, k, m; long double amm, aim;

for (m = 0; m <= n-2; m++) {// m

amm = a[m][m];

for (k = m; k <= n-1; k++)a[m][k] = a[m][k]/amm; // 3.16

b[m] = b[m] / amm;

for (i = m + 1; i <= n-1; i++){// i

aim = a[i][m];

for (k = m; k <= n-1; k++)

a[i][k] = a[i][k] - a[m][k]*aim; // 3.17

b[i] = b[i] - b[m]*aim;

} // end i

} // end m

x[n-1] = b[n-1]/a[n-1][n-1]; // 3.19

for (i = n - 2; i >= 0; i--){// i

x[i] = b[i];

for (k = i + 1; k < n; k++) // 3.20

x[i] = x[i] - a[i][k]*x[k];

} // end i

return 0;

} // end gauss

 

Отметим, что в процедуре gauss() массивы исходных данных a и b не сохраняются, так как результаты преобразований записываются в эти же массивы.