高斯消元

高斯消元

设有n个未知数m个方程的线性方程组

\[\begin{cases} a_{11}x_{1}+a_{12}x_{2}+\dots+a_{1n}x{n}=b_{1} \\ a_{21}x_{1}+a_{22}x_{2}+\dots+a_{2n}x{n}=b_2 \\ \dots \dots \\ a_{m1}x_1+a_{m2}x_{2}+\dots+a_{mn}x_{n}=b_m \end{cases} \]

其中\(a_{ij}\)是第i个方程的第j个未知数的系数,\(b_i\)是第i个方程的常数项,\(i=1,2,\dots,m;j=1,2,\dots,n\)

image.png

代码实现

在化简为上三角矩阵的过程之中,通常要保证选择的主元的绝对值尽可能的大,以减小数值计算的精度误差

#include <iostream>
#include <cstring>
#include <queue>
#include <algorithm>
#include <cmath>
#include <stack>
#include <vector>
#include <map>
#include <set>
#include <array>
using namespace std;
#define x first
#define y second
#define eps 1e-6
typedef pair<int, int> PII;
typedef long long LL;
const int N = 220;
double a[N][N],x[N]; //方程左边的矩阵和等式右边的值,求解后x存的就是结果
int equ,var; // 方程数和未知数个数
int n;
//返回0表示无解1表示有解
int Gauss()
{
	// k表示当前判断是否要交换的行号,max_r是包括k当前要寻找的未知数的最大系数的行号
	int i,j,k,col,max_r;
	for(k = 0, col = 0; k < equ && col < var; k++, col++)
	{
		max_r = k;
		for(i = k + 1; i < equ; i++)
			if(fabs(a[i][col]) > fabs(a[max_r][col]))
				max_r = i; // 找到当前未知数的绝对值最大的系数的行号
		if(fabs(a[max_r][col]) < eps) return 0; // 如果系数当前要找的未知数系数等于0,则不管无穷解还是无解均返回0
		if(k != max_r)
		{
			// 将当前行换为绝对值系数最大的那一行
			for(j = col; j < var; j++) 
				swap(a[k][j],a[max_r][j]);
			swap(x[k],x[max_r]);
		}
		// 系数化为1
		x[k] /= a[k][col];
		for(j = col + 1; j < var; j++) a[k][j] /= a[k][col];
		a[k][col] = 1;
		// 将其他行的该位置未知数系数变为0
		for(i = 0; i < equ; i++)
			if(i != k)
			{
				x[i] -= x[k] * a[i][col];
				for(j = col + 1; j < var; j++) a[i][j] -=a[k][j]*a[i][col];
				a[i][col] = 0;
			}
	}
	for(int i = 0; i < n; i++) printf("%.10f\n", x[i] / a[i][i]);
	
	return 1;
}
int main()
{	
	scanf("%d",&n);
	equ = var = n;
	for(int i = 0; i < n; i++)
	{
		for(int j = 0; j < n; j++) scanf("%lf",&a[i][j]);
		scanf("%lf",&x[i]);
	}
	if(!Gauss()) printf("-1\n");

	return 0;
}

简单应用

求行列式的值

  • 将矩阵A进行高斯消元,交换两行时sgn*=-1(符号)
  • 最后将对角线上的值全部相乘,再乘以sgn即可

矩阵求逆

  • 将矩阵A和单位矩阵E横向链接,然后进行高斯消元
  • 将A编程单位矩阵时,E就变成了A的逆矩阵\(A_1\)

例题

image.png

#include <iostream>
#include <cstring>
#include <queue>
#include <algorithm>
#include <cmath>
#include <stack>
#include <vector>
#include <map>
#include <set>
#include <array>
using namespace std;
#define x first
#define y second
#define eps 1e-6
typedef pair<int, int> PII;
typedef long long LL;
const int N = 220;
double a[N][N],x[N]; //方程左边的矩阵和等式右边的值,求解后x存的就是结果
int equ,var; // 方程数和未知数个数
int n;
//返回0表示无解1表示有解
int Gauss()
{
	// k表示当前判断是否要交换的行号,max_r是包括k当前要寻找的未知数的最大系数的行号
	int i,j,k,col,max_r;
	for(k = 0, col = 0; k < equ && col < var; k++, col++)
	{
		max_r = k;
		for(i = k + 1; i < equ; i++)
			if(fabs(a[i][col]) > fabs(a[max_r][col]))
				max_r = i; // 找到当前未知数的绝对值最大的系数的行号
		if(fabs(a[max_r][col]) < eps) return 0; // 如果系数当前要找的未知数系数等于0,则不管无穷解还是无解均返回0
		if(k != max_r)
		{
			// 将当前行换为绝对值系数最大的那一行
			for(j = col; j < var; j++) 
				swap(a[k][j],a[max_r][j]);
			swap(x[k],x[max_r]);
		}
		// 系数化为1
		x[k] /= a[k][col];
		for(j = col + 1; j < var; j++) a[k][j] /= a[k][col];
		a[k][col] = 1;
		// 将其他行的该位置未知数系数变为0
		for(i = 0; i < equ; i++)
			if(i != k)
			{
				x[i] -= x[k] * a[i][col];
				for(j = col + 1; j < var; j++) a[i][j] -=a[k][j]*a[i][col];
				a[i][col] = 0;
			}
	}
	for(int i = 0; i < n; i++) printf("%.10f\n", x[i] / a[i][i]);
	
	return 1;
}
int main()
{	
	scanf("%d",&n);
	equ = var = n;
	for(int i = 0; i < n; i++)
	{
		for(int j = 0; j < n; j++) scanf("%lf",&a[i][j]);
		scanf("%lf",&x[i]);
	}
	if(!Gauss()) printf("-1\n");

	return 0;
}

image.png

image.png

// Problem: 开关问题
// Contest: Virtual Judge - POJ
// URL: https://vjudge.net/problem/POJ-1830
// Memory Limit: 29 MB
// Time Limit: 1000 ms
// 
// Powered by CP Editor (https://cpeditor.org)

#include <iostream>
#include <cstring>
#include <queue>
#include <algorithm>
#include <cmath>
#include <stack>
#include <vector>
#include <map>
#include <set>
#include <array>
using namespace std;
#define x first
#define y second
typedef pair<int, int> PII;
typedef long long LL;
int n,test,c[101],d[101];
int a[101][101],b[101];

void gauss()
{
	int l = 1;
	for(int i = 1; i <= n; i++)
	{
		for(int  j = l; j <= n; j++)
			if(a[j][i])
			{
				for(int k = i; k <= n; k++)
					swap(a[j][k], a[l][k]);
				swap(b[j],b[l]);
				break;
			}
		if(!a[l][i]) continue;
		for(int j = 1; j <= n; j++)
		{
			if(j != l && a[j][i])
			{
				for(int k = i; k <= n; k++)
					a[j][k] ^= a[l][k];
				b[j] ^= b[l];
			}
		}
		l++;
	}
	for(int i = l; i <= n;i++)
	{
		if(b[i])
		{
			printf("-1\n");
			return ;
		}
	}
	printf("%d\n", 1 << (n-l+1));
}

int main()
{	
	scanf("%d",&test);
	while(test--)
	{
		scanf("%d",&n);
		for(int i = 1; i <= n; i++) scanf("%d",&c[i]);
		for(int i = 1; i <= n; i++) scanf("%d",&d[i]);
		for(int i = 1; i <= n; i++) b[i] = c[i]^d[i];
		memset(a,0,sizeof(a));
		for(int i = 1; i <= n; i++) a[i][i] = 1;
		int x,y;
		while(scanf("%d%d",&x,&y),x && y)
			a[y][x] = 1;
		gauss();
	}

	return 0;
}
posted @ 2023-12-21 19:04  viewoverlook  阅读(8)  评论(0编辑  收藏  举报