//高斯消元 //概念什么的都理解,具体实现? //先打板子 #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; }