注意 这是一个十分毒瘤的板子,纯手打。慎入!有兴趣者可以看看(手动狗头)
距离上一篇归来好久了,虽说要复习,但是有课啊(呵呵)。上周结了一部分课程,所以有空来肝一肝了。
然后呢关于高斯消元法的道理也不是我能说清的,上了大学学了线代自然就懂了(当年就是高中一直搞不懂原理,只能理解加加减减消元解方程,所以一直没理解矩阵的秩,向量的线性相关,判断无解和无穷解这些东西)。所以这里不讲原理。高中小同学门要搞懂原理得看看有关数学的书,线性代数前面关于矩阵这些只要好好学习了书本高中还是能接受的,要不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()函数即可。
如果有多组数据,记得每次初始化。