P3389 模板高斯消元法
Posted garen-wang
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了P3389 模板高斯消元法相关的知识,希望对你有一定的参考价值。
刷模板多好啊,不用动脑。。。
新学习了高斯消元。
其实高斯消元就是把我们小学就学过的解方程组用程序语言表达出来了而已。
小学学的东西有加减法,代入法。我们这里都会用到。
但是也挺难记的
给你三个形如ax+by+cz=d,怎么求出答案?n个呢?
所以还是老老实实地学习一下高斯消元。
首先,我们程序只能记录下一条方程的系数,用二维数组存下来。不然教我自变量怎么存
我们程序分为(n)个循环,因为我们共有(n)个未知数和方程。
根据我的理解,第(i)个循环是化简第(i)个方程式,使之只含有(n - i + 1)个未知数。
每一次循环,我们最重要的一个数字是(a[i][i])!因为我们的目标是把它化为1。
在正事之前,先做一个优化:将第(i)项系数最大的方程移动到第(i)行。听别人说可以减小误差。
接下来要做的事情是:将这个第(i)行的第(i)个系数化为1。
做法也非常简单,不过注意一下:最终得到的矩阵,第(i)行的前(i - 1)个变量的系数都为0!这样的操作支持回带。
所以从第(i)位到(n+1)位同除以a[i][i]。这样就可以把第(i)个系数化为1。
然后求出这么一个方程,就可以为下面方程的化简做铺垫。
我们可以约掉这个方程下面那个方程的第(i)位系数。如何操作?
很简单。只需要记忆一个div为第(i+1)个方程的第(i)个系数,然后第(i)个方程左右同乘以div,得到的第(i)位系数会与第(i+1)位的一致,运用加减法,减掉就可以了。
最终求出来的矩阵,因为每一次运用加减法可以消掉一个变量,所以最终长成这样:
1.00 0.33 0.22 0.22
0.00 1.00 1.85 0.76
0.00 0.00 1.00 -2.39
很容易就能发现最后一个x的值就是-2.39是吧。
所以我们可以从下往上回带,每一次回带就能求出一个x的值。
具体操作也很简单,等式两边同时减掉(系数( imes)变量值),用循环实现。
好的,终于讲完了。
今晚要试试,重新打一下。
在此对@皎月半洒花 表示忠心的感谢。我永远喜欢花姐姐
花姐姐不会看到我这个蒟蒻的博客,所以放心的写。。。
忘记贴代码了,我贴:
#include<cstdio>
#include<cmath>
#include<algorithm>
const int maxn = 115;
const double eps = 1e-7;
double a[maxn][maxn];
double ans[maxn];
int n;
int main()
{
scanf("%d", &n);
for(int i = 1; i <= n; i++)
{
for(int j = 1; j <= n + 1; j++)
{
scanf("%lf", &a[i][j]);
}
}
for(int i = 1; i <= n; i++)
{
int r = i;
for(int j = i + 1; j <= n; j++)
{
if(fabs(a[j][i]) > fabs(a[r][i])) r = j;
}
if(fabs(a[r][i]) < eps)
{
printf("no solution
");
return 0;
}
if(r != i) std::swap(a[r], a[i]);
double div = a[i][i];
for(int j = i; j <= n + 1; j++) a[i][j] /= div;
for(int j = i + 1; j <= n; j++)
{
div = a[j][i];
for(int k = i; k <= n + 1; k++)
{
a[j][k] -= a[i][k] * div;//pay attention to here
}
}
}
ans[n] = a[n][n + 1];
for(int i = n - 1; i >= 1; i--)
{
ans[i] = a[i][n + 1];
for(int j = i + 1; j <= n; j++)
{
ans[i] -= ans[j] * a[i][j];
}
}
for(int i = 1; i <= n; i++) printf("%.2lf
", ans[i]);
return 0;
}
以上是关于P3389 模板高斯消元法的主要内容,如果未能解决你的问题,请参考以下文章