[洛谷P3389][模板]高斯消元法

先贴一段百科

  数学上,高斯消元法,是线性代数规划中的一个算法,可用来为线性方程组求解。但其算法十分复杂,不常用于加减消元法,求出矩阵的秩,以及求出可逆方阵的逆矩阵。不过,如果有过百万条等式时,这个算法会十分省时。一些极大的方程组通常会用迭代法以及花式消元来解决。当用于一个矩阵时,高斯消元法会产生出一个“行梯阵式”。高斯消元法可以用在电脑中来解决数千条等式及未知数。

计算机实现高斯消元法其实利用了矩阵的性质,关于矩阵和行列式的性质见某度百科:

      行列式 https://baike.baidu.com/item/%E8%A1%8C%E5%88%97%E5%BC%8F 

      矩阵 https://baike.baidu.com/item/%E7%9F%A9%E9%98%B5/18069

对于方程来说,有:

1)两方程互换,解不变;

2)一方程乘以非零数k,解不变;

3)一方程乘以数k加上另一方程,解不变

根据这三项性质, 我们可将方程中的各个未知数消去, 当方程个数和未知数总数相等时, 我们可以通过消元直接得出一个未知数的值, 这个方程一定是可解的.

对应到行列式, 有行列式的以下性质:

1)对换行列式中两行的位置,行列式反号

2)行列式的某一行乘任一非零数 k 等于用这个数乘此行列式

3)一行加上另一行的k倍,行列式的值不变

根据这三条性质, 我们一定可以通过一系列流程将行列式转化成一个上三角, 那么也就有了在方程中各个未知数的值.

具体的操作流程

      1. 用一个非零的数乘矩阵的某一行

      2. 将一行的k倍加到另一行上

      3. 交换矩阵中两行的位置

其他的代码里都写注释了

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<algorithm>
 4 
 5 using namespace std;
 6 
 7 int n;
 8 double a[101][102];
 9 
10 void solve()
11 {
12     int g;
13     for(int i=1;i<=n;i++)//消元循环,i用于检索对角线上各个点的行列
14     {
15         if(!a[i][i])
16         {
17             int r=i; //记录当前所在的行
18             for(r=i+1;r<=n;r++) //寻找当前列上不为零的一行
19                 if(a[r][i])
20                 {
21                     break;
22                 }
23             for(int j=1;j<=n+1;j++)
24                 swap(a[r][j],a[i][j]); //换行
25         }
26         /* 接下来利用高斯消元法求解
27         实际左下的三角形对整个式子的结果无影响,
28         只需根据它们求上下的比例关系 */
29         for(int k=i+1;k<=n;k++) //k用于记录需消元的行 
30             for(int j=n+1;j>=i;j--) //j用于记录该行每个需要变化的,用于计算结果的系数
31                 {
32                     a[k][j] -= (a[k][i]/a[i][i])*a[i][j];
33                 }
34                 /*
35                    这里是求出了这一行需要消去的系数和它上面对应的数的
36                    关系,然后按照这个关系对无需消去的数求差,这里一定
37                    是按照三角形消的,因为最外层循环的i在改变,从而就改
38                    变了开始这一“消元”循环的位置,注意用双精
39                 */
40     }
41 
42     for(int i=n;i>=1;i--) //求解循环,从最后一个解倒推
43     {
44         if(!a[i][i])
45         {
46             cout<<"No Solution";
47             return;
48         }
49         for(int j=i+1;j<=n;j++)
50             a[i][n+1] -= a[j][n+1]*a[i][j]; //将解存到等式右边
51         a[i][n+1]/=a[i][i]; //最后的值除以当前的未知数的系数
52     }
53 
54     for(g=1;g<=n;g++)
55         printf("%.2lf
",a[g][n+1]);
56 }
57 
58 int main()
59 {
60     int pl;
61     ios::sync_with_stdio(false);
62     cin>>n;
63     for(int i=1;i<=n;i++)
64         for(int j=1;j<=n+1;j++)
65             cin>>a[i][j];
66     solve();
67 
68     return 0;
69 }

在这里感谢Moster_Yi神仙的指导QwQ

原文地址:https://www.cnblogs.com/Foggy-Forest/p/12203194.html