高斯消元的板子

//高斯消元
//概念什么的都理解,具体实现?
//先打板子
#include <cstdio>
#include <iostream>
#include <algorithm>
#include <cstring>
#include <cmath>
using namespace std;
const int mx=200;
const double eps=1e-7;//处理double的精度
int n;
double g[mx][mx];
double ans[mx];
void Gausswork1(){
for(int i=1;i<=n;++i){
int r=i;
//第一个括号是行,第二个是列
for(int j=i+1;j<=n;++j){
if(fabs(g[r][i])<fabs(g[j][i])){
r=j;
//这里列没有动,循环了行,ok
}
}
//这个地方理解,我们要消掉第一列,就找到第一列里系数最大的那一行
//要消掉第二列,就从第二行开始到第二列系数最大的那一行
//不从第一行找是因为第一行是上次找的那个,已经被我们移上去了,不需再修改
//最终构成一个上三角矩阵
//系数绝对值最大的方程转移到被减的这一行,这样就可以减小误差,说是减小误差,其实好像
//也没有什么别的意义的
if(fabs(g[r][i])<eps){
printf("No Solution\n");
return ;//这里就是说白了,每做完一次,就判断一下秩,不用等最后再数了
//它已经是最大的了,它为0,这一个xi必定无解或无数解,如果最后模拟下来
//最后就是第一行5个数,第二行3个数,总之会剩下一行为零,致使秩不为n
//题干还说无解和无数解都是no,所以这里直接这样写
}
if(i!=r)swap(g[i],g[r]);//这个操作记住,这里应该是默认对换行
double div=g[i][i];
//将正在处理的方程式化简,让正被处理的系数化1
for(int j=i;j<=n+1;++j){
g[i][j]/=div;
//把最大那个系数换为1,同时它除了,自己这一行都要除
}
//使用加减法,将下面的所有行的当前i列(也是处理行的行),的值都化为0
for(int j=i+1;j<=n;++j){
div=g[j][i];//无耻暴力消元法,把敌人强行拉到同一水平线
//这里取出了消元用行在当前消元行之下每一行的第i列那个数,
for(int k=i;k<=n+1;++k){
g[j][k]-=g[i][k]*div;
//目前这一行的在i列后的每一个数,都减去消元用行的当前这个数乘上这一行的第i个数
//或者这么理解,一开始肯定是div-1*div=0;正好把首位消掉了,消掉了其它位依次做方程加减
//这个我得再理解理解
}
}
}
//下面就是回带
ans[n]=g[n][n+1];//消到最后这个值就是xn的答案了,因为它这一行就剩它了
for(int i=n-1;i>=1;i--){
ans[i]=g[i][n+1];
for(int j=i+1;j<=n;++j){
ans[i]-=(g[i][j]*ans[j]);//这没有啥了,把前面求出来的已知答案乘上系数
//最后剩下当前的就是答案
}
}
for(int i=1;i<=n;++i){
printf("%.2lf\n",ans[i]);
}
//这个时间复杂度是n的三次方
}
void Solve(){
scanf("%d",&n);
for(int i=1;i<=n;++i){
for(int j=1;j<=n+1;++j){
scanf("%lf",&g[i][j]);
}
}
Gausswork1();
}
int main(){
Solve();
return 0;
}
  

 

posted @ 2022-02-24 07:54  SMTwy  阅读(57)  评论(0编辑  收藏  举报