Вопрос № 172614: Здравствуйте, уважаемые Эксперты! Срочно нужна Ваша помощь! Для решения одной из моих задач мне нужно найти решение системы линейных уравнений методом Гаусса. Поискав в интернете нашел _один_ распространенный алгоритм (приведу ег...
Вопрос № 172614:
Здравствуйте, уважаемые Эксперты!
Срочно нужна Ваша помощь!
Для решения одной из моих задач мне нужно найти решение системы линейных уравнений методом Гаусса.
Поискав в интернете нашел _один_ распространенный алгоритм (приведу его ниже). НО! Он работает только для матриц с ненулевыми значениями.
Я точно знаю, что методом Гаусса можно решить и с нулевыми, но такого примера не нашел.
Если у кого есть прошу поделитесь, пожалуйста. (Матрица n*n +значения). Т около 1000.
приведенный ниже алгоритм для не нулевых значений нормально отрабатывается за 3 секунды.
procedure TForm3.Button1Click(Sender: TObject); var a: Matrix; b,x: Vector; h: Double; i,j,k,n:integer; begin //Ввод данных //Размерность системы n := StrToIntDef(Text, StringGrid1.ColCount); /
/Коэффициенты for j := 0 to n - 1 do for i := 0 to n - 1 do a[i + 1, j + 1] := StrToFloatDef(StringGrid1.Cells[j, i], 0); //Правая часть уравнения for I := 0 to n - 1 do b[i + 1] := StrToFloatDef(StringGrid2.Cells[0, i], 0); //Прямой ход - исключение переменных for i:=1 to n-1 do for j:=i+1 to n do begin a[j,i]:=-a[j,i]/a[i,i]; for k:=i+1 to n do a[j,k]:=a[j,k]+a[j,i]*a[i,k]; b[j]:=b[j]+a[j,i]*b[i] end;
x[n]:=b[n]/a[n,n]; //Деление на ноль //Обратный ход - нахождение корней for i:=n-1 downto 1 do begin h:=b[i]; for j:=i+1 to n do h:=h-x[j]*a[i,j]; x[i]:=h/a[i,i] end; //Вывод результата for i:=1 to n do ListBox1.Items.Append('x(' + IntToStr(i) + ')=' + FloatToStr(x[i])); end;
procedure TForm3.Edit1Change(Sender
: TObject); begin with StringGrid1, Edit1 do begin ColCount := StrToIntDef(Text, 3); RowCount := StrToIntDef(Text, 3); end; with StringGrid2, Edit1 do RowCount := StrToIntDef(Text, 3) end;
procedure TForm3.FormCreate(Sender: TObject); var i, j: integer; begin //Заполнить коэф уравнения Randomize; for I := 0 to StrToIntDef(Text, StringGrid1.ColCount) - 1 do for J := 0 to StrToIntDef(Text, StringGrid1.RowCount) - 1 do
StringGrid1.Cells[I, J] := IntToStr(Random(100)); for I := 0 to StrToIntDef(Text, StringGrid2.RowCount) - 1 do StringGrid2.Cells[0, I] := IntToStr(Random(100)) end;
end.
Отправлен: 25.09.2009, 14:16
Вопрос задал: LanK, Профессионал
Всего ответов: 1 Страница вопроса »
Отвечает Сергей Бендер, 1-й класс :
Здравствуйте, LanK.
1) Непонятно, почему у тебя написано "Деление на ноль" в строчке с делением на a[n,n]. Оно, как правило, должно происходить раньше, в цикле при делении на a[i,i]
2) Напутано с алгоритмом - правильного ответа быть не должно. После a[j,i]:=-a[j,i]/a[i,i]; надо делать такое же деление для b b[j]:=-b[i]/a[i,i];
А строчка b[j]:=b[j]+a[j,i]*b[i] должна, во первых, находиться в цикле (у тебя нет begin end), во вторых, просчитывать k-й (а не j-й)
элемент, т.е.: b[k]:=b[k]+a[j,i]*b[k]
3) Обратный ход вполне можно делать от n: for i:=n downto 1 do а строчку x[n]:=b[n]/a[n,n]; преспокойно стирать. Избыточна.
4) Теперь о нулевых диагональных элементах. Это нужен алгоритм с выбором столбцов. Собственно никакого особого алгоритма тут нет. Просто у системы можно без нарушения эквивалентности менять местами столбцы. Главное при это помнить какие столбцы переставлены.
Т.е. перед глав
ным делением a[j,i]:=-a[j,i]/a[i,i]; надо проверить a[i,i] на равнество нулю и, если да, то найти в строке какой-нибудь (например, первый) ненулевой. (Если все нули значит система недоопределени и не имеет единственного решения.) Это можно сделать сразу m:=i; while (a[i,m]<>0) and (m<=n) do inc(m); if m>n then ... // все нули Потом цикл по этим столбцам (от начала, а не от i) for k:=1 to n do begin /// меняем местами a[i,k] и a[m,k] end;
Останется только запоминть,
какие элементы поменял. Это можно держать в массиве вроде ind:array[1..n] of integer; Перед прямым ходом надо его заполнить for i:=1 to n do ind[i]:=i; А результата выводить не как x[i], а как x[ind[i]]. (В принципе, может быть в Делфе уже есть какая-нибудь удобная штука для этого. Не помню.)
Удачи!
Ответ отправил: Сергей Бендер, 1-й класс
Ответ отправлен: 28.09.2009, 21:34
Оценка ответа: 5 Комментарий к оценке: спасибо
Как сказать этому эксперту "спасибо"?
Отправить SMS
#thank 254815
на номер 1151 (Россия) |
Еще номера »
Вам помогли? Пожалуйста, поблагодарите эксперта за это!
Оценить выпуск »
Нам очень важно Ваше мнение об этом выпуске рассылки!
* Стоимость одного СМС-сообщения от 7.15 руб. и зависит от оператора сотовой связи.
(полный список тарифов)
** При ошибочном вводе номера ответа или текста #thank услуга считается оказанной, денежные средства не возвращаются.
*** Сумма выплаты эксперту-автору ответа расчитывается из суммы перечислений на портал от биллинговой компании.