第一章、线性代数(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;
}
相关推荐
NAGNIP2 小时前
一文搞懂CNN经典架构-EfficientNet!
算法·面试
如何原谅奋力过但无声2 小时前
【chap11-动态规划(上 - 基础题目&背包问题)】用Python3刷《代码随想录》
数据结构·python·算法·动态规划
小宇的天下2 小时前
Calibre LVS Circuit Comparison(2)
算法·lvs
迈巴赫车主3 小时前
求最大公约数-欧几里得算法(辗转相除法)
算法·最大公约数
lxl13073 小时前
C++算法(15)BFS_FloodFill
算法·宽度优先
小王C语言3 小时前
【基础IO】————简单设计一下libc库
前端·数据结构·算法
亦复何言??3 小时前
BeyondMimic 论文解析
人工智能·算法·机器人
WolfGang0073213 小时前
代码随想录算法训练营 Day20 | 回溯算法 part02
算法
YXXY3133 小时前
前缀和算法
算法