高斯消元法

本文介绍了高斯消元法的程序实现,重点在于代码实践而非理论原理。作者提醒读者,要理解高斯消元法的数学原理最好参考相关数学书籍。文章提供了洛谷3389题的模板,并指出代码中可能存在的除以0的错误,建议添加额外判断。此外,对于处理多组数据的情况,需注意初始化操作。
摘要由CSDN通过智能技术生成

注意 这是一个十分毒瘤的板子,纯手打。慎入!有兴趣者可以看看(手动狗头)

距离上一篇归来好久了,虽说要复习,但是有课啊(呵呵)。上周结了一部分课程,所以有空来肝一肝了。
然后呢关于高斯消元法的道理也不是我能说清的,上了大学学了线代自然就懂了(当年就是高中一直搞不懂原理,只能理解加加减减消元解方程,所以一直没理解矩阵的秩,向量的线性相关,判断无解和无穷解这些东西)。所以这里不讲原理。高中小同学门要搞懂原理得看看有关数学的书,线性代数前面关于矩阵这些只要好好学习了书本高中还是能接受的,要不noip那么多队佬都是怎么来的。。也不建议大家找这些写高斯消元的重在程序实现的博客来学习,讲的都不会特别深入。亲身体验:原理看书就好。
我这里说的就是实现问题,至于具体的看代码就可,自以为注释加的还算比较详尽了。

题目就是模板题 洛谷3389

不再粘原题了请自行查找。
算了,还是给个链接吧点这里洛谷P3389【模板】高斯消元法

然后代码,来!

/*
这是一个十分毒瘤的高斯消元法板子,大家不要学(手动滑稽)
*/
#include<bits/stdc++.h>
using namespace std;


int n;
double a[110][110];						//a记录系数矩阵,b记录常数列 
double b[110];
int wh[110];				//最为毒瘤的地方,嘿嘿。wh是按正序记录每一列主
					//元所在是第几行 
					//为什么要开这样一个数组  
					//是因为 按照我这个毒瘤写法写完以后并没有化成好看的矩阵 
					//而是一个虽然符合阶梯型规律,但是打乱了行顺序的矩阵 
					//又懒得调整回来,索性给他记录一下,能正常输出就好了 
void guass()
{
	for(int i=1;i<=n;++i){
		double md;int st;			//md记录每行的主元,即这一行元素要除以
									//	什么数,st记录主元所在列位置,每次 
									//	对列操作完都要回到这里开始 
		int j=1;					//j一直记录每次操作到了第几列,i一直 
		for(;j<=n;++j)					//记录操作到第几行 
		if(a[i][j]){st=j;break;}		//寻找本行第一个不为零的数作为主元 
		double now=a[i][j];int w=i;			
		for(int u=i+1;u<=n;++u){
			if(fabs(a[u][j])>fabs(now)){
			now=a[u][j];w=u;
			}								//这一段为了提高精度,寻找每一列
		}									//最大的数作为主元能减小误差?! 
		swap(a[i],a[w]);swap(b[i],b[w]);	 
		md=a[i][j];wh[j]=i;
		for(;j<=n;++j){						//从这开始消元操作,本行元素先除以主元 
			a[i][j]/=md;
		}										
		b[i]/=md;						
		for(int u=i+1;u<=n;++u){
			j=st;
			double mdd=a[u][j];
			for(;j<=n;++j)a[u][j]-=a[i][j]*mdd; 
			b[u]-=b[i]*mdd;    //再乘以要消去行的行首(用mdd记录)并减去
		}
	}
}

void ans()
{
	bool jg=0;
	for(int i=1;i<=n;++i){	
		jg=0;
		for(int j=1;j<=n;++j){
			if(a[i][j]){
				jg=1;break;
			}
		}
		if(!jg){
			printf("No Solution");			//不论b是否为零,只要一行都是零,
			return;									//	说明该矩阵的秩小于n(无穷的解)
				//	或者存在矛盾方程(无解) 							
				//	(只针对于洛谷模板题来说,反正都让输出no solution)
				//如果对两种情况加以区分,再判断一些b即可 
		}		
	}
	for(int i=n;i>=1;--i){
		for(int j=i+1;j<=n;++j){
			b[wh[i]]-=b[wh[j]]*a[wh[i]][j];
		}		
		b[wh[i]]/=a[wh[i]][i];	//毒瘤吧?按照wh逆序寻找对应主元列的行
								//然后  是正常的倒带回 操作,输出答案即可 
	}	
	for(int i=1;i<=n;++i){
		printf("%.2lf\n",b[i]);
	}	
} 

int main()
{
	freopen("a.in","r",stdin);
	scanf("%d",&n);
	for(int i=1;i<=n;++i){
		for(int j=1;j<=n;++j)
			scanf("%lf",&a[i][j]);
		scanf("%lf",&b[i]);
	}
	guass();
	ans();
	return 0;	
}

然后因为某些原因,发现了一点bug。果然洛谷本题的数据较水。这个代码没有判断一行全部消完的情况,可能会导致除以0然后re发生。所以,可以在寻找改行不为零的数那一行代码后加上一段

	if(!a[i][j]){
			printf("");	//此时一行都是零,看看b如果也是零则无穷解,否则无解 
			e=1;
			return;
		}	 

并且在开头开上一个bool变量e,判断是否出现该情况,如果有,直接在主函数中跳过ans()函数即可。
如果有多组数据,记得每次初始化。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值