第一章、线性代数(2)高斯消元法

一、线性方程组

【线性方程组】

线性方程组是由n个m元一次方程共同构成。比如n = 3,m = 3时,有线性方程组:

如果把系数拿出来,就构成系数矩阵

将系数和常数项拿出来,就构成增广矩阵

二、高斯消元法

【高斯消元法】

高斯消元法是求解线性方程组的经典方法。除了用于线性方程组的求解之外,还可以用于行列式的计算、求矩阵的逆以及其他计算机工程方面。

高斯发现,在求解线性方程组时,当未知数排列整齐后,求解的过程只与系数和常数项有关。因此,只需要对增广矩阵执行相应操作即可。

其中,对增广矩阵执行下述三类操作,不会影响方程组的解:

1、交换两行;

2、某一行所有元素乘以一个数k,其中k不等于0;

3、将某一行所有元素的k倍加到另一行对应元素上。

这三种操作被称为矩阵的初等行变换。

【代码实现】

cpp 复制代码
const int N = 110;
const double eps = 1e-7;

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

inline bool zero(double x)
{
	return fabs(x) < eps;
}

int gauss()
{
	for(int i = 1; i <= n; i++)
	{
		int aim = i;
		// 找出第i列中,未确定主元的行中的最大行
		for(int j = 1; j <= n; j++)
		{
			// 判断是否确定主元
			if(j < i && !zero(a[j][j]))
				continue;
				
			if(fabs(a[j][i]) > fabs(a[aim][i]))
				aim = j;
		}
		
		if(zero(a[aim][i]))
			continue;
		
		// 交换aim行和i行	
		for(int j = 1; j <= n + 1; j++)
			swap(a[aim][j], a[i][j]);
		
		// a[i][i] 置为1	
		for(int j = n + 1; j >= i; j--)
			a[i][j] /= a[i][i];
		
		// 第i列除了第i行,全部消为0
		for(int j = 1; j <= n; j++)
		{
			if(j == i)
				continue;
				
			double t = a[j][i] / a[i][i];
			for(int k = i; k <= n + 1; k++)
			{
				a[j][k] -= a[i][k] * t;
			}
		}
	}
	
	// 判断解
	int ret = 1;  // 唯一解
	for(int i = 1; i <= n; i++)
	{
		if(zero(a[i][i]) && !zero(a[i][n + 1]))
		{
			ret = 0;  // 无解
			break;
		}
		if(zero(a[i][i]))
			ret = 2;  // 无数解
	}
	return ret;
}

三、矩阵求逆

cpp 复制代码
#define  _CRT_SECURE_NO_WARNINGS 1
#include <iostream>
#include <algorithm>
using namespace std;

const int N = 410, mod = 1e9 + 7;
const double eps = 1e-7;
typedef long long LL;

int n;
LL a[N][N + N];

LL qpow(LL a, LL b, LL p)
{
	LL ret = 1;
	while (b)
	{
		if (b & 1)
			ret = ret * a % p;

		b >>= 1;
		a = a * a % p;
	}
	return ret;
}

int gauss()
{
	for (int i = 1;i <= n;i++)
	{
		int aim = i;
		for (int j = 1;j <= n;j++)
		{
			if (j < i && a[j][j] != 0)
				continue;

			if (a[j][i] > a[aim][i])
				aim = j;
		}

		if (a[aim][i] == 0)
			return 0;

		for (int j = 1;j <= n + n;j++)
			swap(a[aim][j], a[i][j]);

		LL t = qpow(a[i][i], mod - 2, mod);
		for (int j = n + n;j >= i;j--)
			a[i][j] = a[i][j] * t % mod;

		for (int j = 1;j <= n;j++)
		{
			if (i == j)
				continue;

			t = a[j][i];
			for (int k = i;k <= n + n;k++)
			{
				a[j][k] -= a[i][k] * t;
				a[j][k] = (a[j][k] % mod + mod) % mod;
			}
		}
	}

	return 1;
}

int main()
{
	cin >> n;
	for (int i = 1;i <= n;i++)
	{
		for (int j = 1;j <= n;j++)
		{
			cin >> a[i][j];
		}
	}

	for (int i = 1;i <= n;i++)
		a[i][i + n] = 1;

	int ret = gauss();
	if (ret == 0)
		cout << "No Solution" << endl;
	else
	{
		for (int i = 1;i <= n;i++)
		{
			for (int j = n + 1;j <= n + n;j++)
			{
				cout << a[i][j] << " ";
			}
			cout << endl;
		}
	}

	return 0;
}
相关推荐
BothSavage13 小时前
Trae远程开发中DeepSeek自定义模型4054错误的排查与修复
算法
小林ixn13 小时前
从暴力到KMP:一道题彻底搞懂字符串匹配的前世今生
算法
烬羽15 小时前
字符串算法入门:从反转字符串到回文判断,面试不再慌
算法·面试
先吃饱再说1 天前
判断回文字符串,从一行代码到双指针优化
算法
黄敬峰1 天前
深入理解算法核心:从递归思想、数组扁平化到快速排序
算法
得物技术1 天前
从狂野代码到按目标生产:得物推荐 AI Harness 的工程化实践|AICon 演讲整理
人工智能·算法·架构
AI小老六2 天前
SkillOpt 架构拆解:把 Skill 文本当参数,用执行轨迹训练 Agent
后端·算法·ai编程
胡萝卜术2 天前
从“分数打架”到“排名投票”:为什么你的ChatBI必须用RRF?
算法·设计模式·面试