• 线性方程组之高斯消元


    一、形式

    (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]线性方程组

    五、总结

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

  • 相关阅读:
    C#数据类型
    面试常备题素数的判断
    Eclipse输入命令行参数
    Socket编程第一步PC上服务器回显客户端发送的字符串
    C# 格式化输出
    截止至2004年8月1日全球CCIE人数统计
    什么是3G?
    DoS 拒绝服务攻击专题
    我的Blog音乐版~~
    国庆啊~~累得我好苦啊~~~
  • 原文地址:https://www.cnblogs.com/ShuraEye/p/11354533.html
Copyright © 2020-2023  润新知