zoukankan      html  css  js  c++  java
  • 线性方程组之高斯消元

    一、形式

    (egin{cases} A_{11}X_{1} + A_{12}X_{2} + ......+A_{1n}X_{n}=B_{1} \ A_{21}X_{1} + A_{22}X_{2} + ......+A_{2n}X_{n}=B_{2}\ ...... A_{n1}X_{1} + A_{n2}X_{2} + ......+A_{nn}X_{n}=B_{n} end{cases})

    上列方程组:

    (A=)(egin{bmatrix} A_{11} & cdots & A_{1n} \ vdots & vdots & vdots \ A_{n1} & cdots & A_{nn} end{bmatrix})

    (B=)(egin{bmatrix} B_{1} \ vdots \ B_{n} end{bmatrix})

    (X=)(egin{bmatrix} X_{1} \ vdots \ X_{n} end{bmatrix})

    可以看作为:(AX=B)

    二、初等变换(行)

    1.将某行同乘或同除一个数(非0)
    2.将某行加到另一行
    3.将任意两行互换

    值都不变(相信大家都知道)

    三、步骤

    大家可以发现,解线性方程其实相当于解小学方程,于是我们的步骤就是相当于模拟小学方程解法

    1.消元

    我们考虑对于第(i)个方程,我们消元消掉(X_{i})

    于是我们需要找到每一个方程中,找到对于(X_i)的最大系数(maxn)以及其对应的方程,将它与第(i)个方程调换,这样能够保证最大系数的(X_i)处理次数最少,时间最少。

    找到最大系数后,我们需要判断一下(maxn)是否等于0,如果等于0就代表没有解。但是因为使用(double)类型,要考虑下精度问题,所以判断条件为小于(eps)

    for(int i=1;i<=n;i++)
    {
    	int now=i;
    	for(int j=i+1;j<=n;j++)
    	{
    		if(fabs(a[now][i])<fabs(a[j][i]))now=j;//寻找x[i]的最大系数
    	}
    	if(fabs(a[now][i])<eps)//判断,如果x[i]的系数小于eps,说明x[i]=0,判断为无解
    	{
    		puts("No Solution");
    		return 0;
    	}
    	if(i!=now)swap(a[i],a[now]);//将最大系数x[i]所在的方程与第i方程交换 
    

    我们由小学奥数可得,我们若想要把(X_i)消掉,最方便的方法是把所有方程的(X_i)的系数都化为(1),再加减消元即可,在处理过程中需要注意方程中的其他变量也要随之变化

    	dl div=a[i][i];//这就是maxn
    	for(int j=i;j<=n+1;j++)a[i][j]/=div;//先处理以maxn为系数的x[i]所在的方程
    	for(int j=i+1;j<=n;j++)//将其他方程都进行处理
    	{
    		div=a[j][i];//其他方程的x[i]的系数
    		for(int k=i;k<=n+1;k++)
    		{
    			a[j][k]-=div*a[i][k];
    		}		
    	}
    }
    

    这样我们就可以一直循环,处理出最后的(X_n)

    ans[n]=a[n][n+1]/a[n][n];
    

    2.回代

    回代也很好理解,每次都从(n)往回模拟方程代入,处理出每个(X_i)

    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];
    }
    

    整体代码

    #include<bits/stdc++.h>
    using namespace std;
    typedef double dl;
    const int N=110;
    const dl eps=1e-9;
    dl a[N][N],ans[N],x[N][N];
    int n;
    
    int main()
    {
    	scanf("%d",&n);
    	for(int i=1;i<=n+1;i++)
    	{
    		for(int j=1;j<=n;j++)
    		{
    			scanf("%lf",&x[i][j]);
    		}
    	}
    	for(int i=1;i<=n;i++)
    	{
    		for(int j=1;j<=n;j++)
    		{
    			a[i][j]=2*(x[1][j]-x[i+1][j]);
    			a[i][n+1]+=x[1][j]*x[1][j]-x[i+1][j]*x[i+1][j];
    		}
    	}
    	for(int i=1;i<=n;i++)
    	{
    		int now=i;
    		for(int j=i+1;j<=n;j++)
    		{
    			if(fabs(a[now][i])<fabs(a[j][i]))now=j;
    		}
    		if(fabs(a[now][i])<eps)
    		{
    			puts("No Solution");
    			return 0;
    		}
    		if(i!=now)swap(a[i],a[now]);
    		dl 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]-=div*a[i][k];
    			}		
    		}
    	}
    	ans[n]=a[n][n+1]/a[n][n];
    	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("%.3lf ",ans[i]);
    	return 0;
    }
    

    四、判断解

    (A、有唯一解:)最后处理出来的(X_i)的系数不为0并且过程中得出系数不为0

    (B、无解:)在处理过程中发现对于(X_i)(maxn=0)

    (C、无穷解:)最后处理出来的(X_i)的系数为0并且等式右边也为0

    题目:
    P3389 【模板】高斯消元法
    P2455 [SDOI2006]线性方程组

    五、总结

    其实可以发现,高斯消元还是很好理解的,主要难的是前面的怎样推导线性方程组的过程,推导出来后就直接套模板就好了

  • 相关阅读:
    Python 类中方法的内部变量,命名加'self.'变成 self.xxx 和不加直接 xxx 的区别
    用foreach遍历 datagridView 指定列所有的内容
    treeView1.SelectedNode.Level
    YES NO 上一个 下一个
    正则 单词全字匹配查找 reg 边界查找 精确匹配 只匹配字符 不含连续的字符
    抓取2个字符串中间的字符串
    sqlite 60000行 插入到数据库只用不到2秒
    将多行文本以单行的格式保存起来 读和写 ini
    将秒转换成时间格式
    richtextbox Ctrl+V只粘贴纯文本格式
  • 原文地址:https://www.cnblogs.com/ShuraEye/p/11354533.html
Copyright © 2011-2022 走看看