高斯消元

21 篇文章 0 订阅
3 篇文章 0 订阅

高斯消元模板
我们可以这样理解高斯消元:
如:解一个三元方程:

x1+2*x2-x3=6
2*x1+x2-3*x3=9
-x1-x2+2*x3=7

我们可以将其转化成矩阵的形式:

1 2 -1				x1				-6
2 1 -3       *      x2		=  		-9	
-1 -1 2				x3				 7

既然x1,x2,x3是我们要求的未知数,不妨将它们先行舍去,同时将等式右边的数加入到左侧的矩阵内,这就是增广矩阵:

1 2 -1 -6	I
2 1 -3 -9	II
-1 -1 2 7	III

接下来,要解出这几个方程,我们先要了解矩阵的一些基本操作:
初等行(列)变换:
1.交换两行
2.把某一行i的所有元素都乘以k
3.把某一行i的所有元素对应加到j行的所有元素
接下来,我们可以明确我们的目标:
既然该矩阵表示的是

x1+2*x2-x3=6
2*x1+x2-3*x3=9
-x1-x2+2*x3=7

所以当我们把该矩阵化简成如下矩阵(k1,k2,k3等为常数):

k1	k2	k3	k4
0	k5	k6	k7
0	0	k8	k9

易知该矩阵表示如下等式:

k1*x1+k2*x2+k3*x3=k4
0*x1+k4*x2+k5*x3=k7
0*x1+0*x2+k8*x3=k9

从第三个式子中我们可解出x3
再推到第二个式子我们可解出x2
再推到第一个式子我们可解出x1
观察该矩阵中的“0”
可发现这呈阶梯状,它的名字为阶梯矩阵。
所以我们可以逐渐这么推:

1 2 -1 -6
2 1 -3 -9
-1 -1 2 7
1 2 -1 6
0 -3 -1 3
0 1 1 1
1 2 -1 -6
0 -3 -1 3
0 0 2/3 2

其实在这里我们就可以解出x1,x2,x3的具体值了,但我们可以进一步推成更加理想的形式:

1 2 -1 -6
0 1 1/3 -1
0 0 1 3
1 2 -1 -6
0 1 0 -2
0 0 1 3
1 0 0 13
0 1 0 -2
0 0 1 3

不难发现,这已经变成了一个单位矩阵(除去最右边一列)
综上所述,解多元一次方程组的步骤是:
方程组=>增广矩阵=>阶梯矩阵(初等行变换)=>单位矩阵
此外,可以根据Gauss-Jordan的一个优化:
如这组数据:

x1+2*x2-x3=6
2*x1+x2-3*x3=9
-x1-x2+2*x3=7

我们发现,第一个式子中x1的系数小于第二个式子中x1的系数。所以我们可以交换第一行和第二行,来避免整数除以小数中的精度误差
根据这些步骤,我们可以写出如下代码:

#include <bits/stdc++.h>
using namespace std;
const int maxn=100+10;
double a[maxn][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 maxr=i;
		for(int j=i+1;j<=n;j++)
			if(abs(a[j][i])>abs(a[maxr][i]))
				maxr=j;
		for(int j=1;j<=n+1;j++)
			swap(a[i][j],a[maxr][j]);
		if(a[i][i]==0){
			printf("No Solution\n");
			return 0;
		}
		for(int j=1;j<=n;j++)
			if(j!=i){
				double rate=a[j][i]*1.0/a[i][i];
				for(int k=i+1;k<=n+1;k++)
					a[j][k]-=a[i][k]*rate;
			}
	}
	for(int i=1;i<=n;i++)
		printf("%.2lf\n",a[i][n+1]*1.0/a[i][i]);
	return 0;
}

训练题:
代码:

#include <bits/stdc++.h>
using namespace std;
const int maxn=1000+10;
double a[maxn][maxn],f[maxn][maxn];
int n;
int main(){
	scanf("%d",&n);
	for(int i=1;i<=n+1;i++)
		for(int j=1;j<=n;j++)	
			scanf("%lf",&f[i][j]);
	for(int i=1;i<=n;i++)
		for(int j=1;j<=n;j++){
			a[i][j]=2*(f[i][j]-f[i+1][j]);
			a[i][n+1]+=f[i][j]*f[i][j]-f[i+1][j]*f[i+1][j];
		}
	for(int i=1;i<=n;i++){
		int maxr=i;
		for(int j=i+1;j<=n;j++)
			if(abs(a[j][i])>abs(a[maxr][i]))
				maxr=j;
		for(int j=1;j<=n+1;j++)
			swap(a[i][j],a[maxr][j]);
		if(a[i][i]==0){
			printf("No Solution\n");
			return 0;
		}
		for(int j=1;j<=n;j++)
			if(j!=i){
				double rate=a[j][i]*1.0/a[i][i];
				for(int k=i+1;k<=n+1;k++)
					a[j][k]-=a[i][k]*rate;
			}
	}
	for(int i=1;i<=n;i++)
		printf("%.3lf ",a[i][n+1]*1.0/a[i][i]);
	return 0;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值