高斯消元个人学习记录

链接:P2455 [SDOI2006] 线性方程组 - 洛谷

把整个算法大体上分成几个部分(个人理解)

1:枚举每一列c;(即枚举x, y, z....的系数)

2: 找到每一列的最大值,之后为了方便操作,将最大值的这一行放到第r行

3: 然后将第r行的每个数都除以a[r][c]的系数,目的就是为了让a[r][c]的系数为1,方便后续消元

4: 保证后面的每一行的第c列都变成0,就是在消元;

5: 最后会形成一个类似上三角行列式的东西, 此时消元已经完成了;

6: 通过这个上三角行列式和矩阵迭代回去即可

举个列子

其实可以发现在草稿纸上的模拟就和初中学的解方程基本一样

当然以上是这个方程保证有解的情况,还有两种情况,无解和无限解,我们结合代码来研究

#include <iomanip>
#include <iostream>
#include <cstring>
#include <algorithm>
#include <cmath>
using namespace std;

const int N = 110;
const double eps = 1e-6;

double a[N][N];
int n;

int gauss()
{
	int r, c;
	for(c = 0, r = 0; c < n; c ++) // 枚举每一列c
	{
		int t = r;
		for(int i = r; i < n; i ++)
		{
			if(fabs(a[i][c]) > fabs(a[t][c])) t = i; // 找到每一列的最大值
		}
		
		if(fabs(a[t][c]) < eps) continue;
		
		for(int i = c; i <= n; i ++) swap(a[t][i], a[r][i]); // 将最大值换到第r行
		
		// 注意这里一定要从n枚举到c,不能反过来,否则a[r][c]会被提前覆盖
		for(int i = n; i >= c; i --) a[r][i] /= a[r][c]; // 将枚举的这一列系数变为1
		
		for(int i = r + 1; i < n; i ++)
		{
			if(fabs(a[i][c]) > eps)
			{
				//这里也要倒着枚举,原因同上
				for(int j = n; j >= c; j --)
				{
					a[i][j] -= a[r][j] * a[i][c]; // 消元
				}
			}
		}
		
		r ++;
	}
	
	if(r < n)
	{
		for(int i = r; i < n; i ++)
		{
			if(fabs(a[i][n]) > eps) return 2; // 无解
		}
		return 1; // 无穷解
	}
	
	for(int i = n - 1; i >= 0; i --)
	{
		for(int j = i + 1; j < n; j ++)
		{
			a[i][n] -= a[i][j] * a[j][n];
		}
	}
	return 0; // 有唯一解
}

int main()
{
	cin >> n;
	for(int i = 0; i < n; i ++)
	{
		for(int j = 0; j <= n; j  ++) 
		{
			cin >> a[i][j];
		}
	}
	
	int t = gauss();
	int cnt = 0;
	if(t == 0)
	{
		for(int i = 0; i < n; i ++)
		{
			cout << "x" << ++ cnt << "=" << fixed << setprecision(2) << a[i][n] << '\n';
		}
	}
	
	else if(t == 1) cout << 0 << '\n';
	else cout << -1 << '\n';
	
	return 0;
}

这里可以看到,当r < n时,方程要么无解,要么有无限解,那么是什么原因导致了r < n呢? 原因就在于有一项列(x, y, z)的系数全为0, 我们假设z的系数为0, 那么最后一行是不是 0 == 一个数, 当然如果这个数是非0的数,那么就说明无解,如果恰好是 0 == 0, 那么我们也无法确定这个z的值,这就导致了x, y也无法确定,也就是有无穷多个解.

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值