[模板]高斯消元法

一、题目

普通版高斯消元
升级版高斯消元

二、解法

分条讲一下高斯消元的思路吧,可能不会太严谨,但是尽量通俗易懂吧:

  • 枚举我们需要消去的未知数 x i x_i ,我们选择 a ( i , i ) a(i,i) 去消掉其他行的 a ( j , i ) a(j,i) ,只留下 a ( i , i ) a(i,i) ,为避免精度问题,我们需要选择最大的 a ( j , i ) a(j,i) j i j\geq i ),然后交换 j , i j,i 行(除法中的除数尽量的大)。
  • 如果交换后的 a ( i , i ) a(i,i) 几乎等于0(我们的判断都要基于 e p s eps (最小进度误差)展开),那么就可以判断为无解或者是无穷多解,我们打上标记,然后跳过 x i x_i ,继续消元,方便我们最后对于无解和无穷多解的判断。
  • 然后就是消元了,消元的方法为枚举要消的行 j j 和列 k k ,那么就可以让a[j][k]-=a[i][k]*a[j][i]/a[i][i];
  • 消完之后判断是否有标记,如果有标记,我们遍历整个矩阵,如果有一行的 x x 系数均为 0 0 且等于的值不为 0 0 ,那么就可以判断为无解,否则就有无穷多组解。
  • 矩阵已经被我们消成了对角线,我们用a[i][n+1]/a[i][i]即可算出 x i x_i 的值。

高斯消元被我写成了一个函数,传入要消的矩阵大小和矩阵,在传入存解的数组,即可得到解,返回值是 1 -1 代表着无穷多解, 0 0 代表者无解, 1 1 代表着有解,个人觉得讲得很清楚了,看代码(sdoi2006)吧。

#include <cstdio>
#include <iostream>
#define eps 1e-7
#define db double 
const int M = 105;
using namespace std;
int read()
{
	int x=0,flag=1;char c;
	while((c=getchar())<'0' || c>'9') if(c=='-') flag=-1;
	while(c>='0' && c<='9') x=(x<<3)+(x<<1)+(c^48),c=getchar();
	return x*flag;
}
int n;db a[M][M],b[M];
int cmp(db x,db y)
{
	if(x-y>eps) return 1;
	if(x-y<-eps) return -1;
	return 0;
}
bool gauss(int n,db a[][M])
{
	bool flag=1;
	for(int i=1;i<=n;i++)
	{
		int Max=i;
		for(int r=i+1;r<=n;r++)
			if(cmp(a[Max][i],a[r][i])==-1)
				Max=r;
		swap(a[i],a[Max]);
		if(cmp(a[i][i],0)==0)
		{
			flag=0;
			continue;
		}
		for(int j=1;j<=n;j++)
		{
			if(i==j || cmp(a[j][i],0)==0) continue;
			for(int k=i+1;k<=n+1;k++)
				a[j][k]-=a[i][k]*a[j][i]/a[i][i];
			a[j][i]=0;
		}
	}
	return flag;
}
int get(int n,db a[][M],db *b)
{
	if(!gauss(n,a))
	{
		for(int i=1;i<=n;i++)
		{
			bool flag=1;
			for(int j=1;j<=n;j++)
				if(cmp(a[i][j],0)!=0)
					flag=0;
			if(flag && cmp(a[i][n+1],0)!=0)
				return -1;
		}
		return 0;
	}
	for(int i=1;i<=n;i++)
		b[i]=a[i][n+1]/a[i][i];
	return 1;
}
int main()
{
	n=read();
	for(int i=1;i<=n;i++)
		for(int j=1;j<=n+1;j++)
			scanf("%lf",&a[i][j]);
	int g=get(n,a,b);
	if(g==-1)
	{
		puts("-1");
		return 0;
	}
	if(g==0)
	{
		puts("0");
		return 0;
	}
	for(int i=1;i<=n;i++)
		printf("x%d=%.2lf\n",i,b[i]);
}
发布了192 篇原创文章 · 获赞 12 · 访问量 3354

猜你喜欢

转载自blog.csdn.net/C202044zxy/article/details/103777723