https://www.luogu.com.cn/problem/P3389

主元消元法【模板】

高斯消元是解决多元线性方程组的方法,再学习它之前,先引入一个东西——行列式


行列式的性质:

这里我们只说其中的两条:

①行列式中的一行,加上另一行的\(k\)倍,行列式的值不变

②交换行列式的两行,行列式的值会变为原来的相反数

每一个有唯一解的线性方程,都拥有一个与其对应的行列式

//如果想详细学习行列式,可以自行上网百度~

目的:为了方便求解,利用①性质,我们可以把它消成上三角行列式(矩阵的对角线的左下方都是\(0\)),其实通俗来讲,就是平时我们学的加减消元法


具体步骤:

①枚举\(1-n\)行

②用第i行的第i列(对角线上的数)来消\(i+1-n\)行的第\(i\)列数,即:将这些数都加上\(k\times c[i][i]\;\;(k=-\frac{c[j][i]}{c[i][i]})\)

这里必须要注意,\(c[i][i]\)不能是\(0\),导致没有意义。所以在算倍数k之前,要保证\(c[i][i]≠0\),即从\(i-n\)行中找到一个数,使得\(c[j][i]≠0\),然后将这两个行的数交换过来即可

根据行列式性质②,行列式的值要变号,但这里我们是在求方程组,不用管行列式值符号的问题

③然后,自下向上递推。从而求出每一个未知数的解

代码:

  1. void gauss()
  2. {
  3. for(int i=1;i<=n;i++)
  4. {
  5. for(int j=i;j<=n;j++)
  6. if(fabs(c[j][i])>1e-8)
  7. //找到大于0的除
  8. {
  9. if(j==i)break;
  10. for(int l=1;l<=n+1;l++)
  11. swap(c[j][l],c[i][l]);
  12. break;
  13. }
  14. if(fabs(c[i][i])<=1e-8)continue;
  15. //如果这列已经全是0了,不必继续消了
  16. for(int j=i+1;j<=n;j++)
  17. {
  18. double k=c[j][i]/c[i][i];
  19. for (int l=1;l<=n+1;l++)
  20. c[j][l]=c[j][l]-c[i][l]*k;
  21. //k(倍数),把这列的数都消成0
  22. }
  23. }
  24. }

但是这种方法可能会存在精度的问题,算\(k\)(倍数)时出现误差

如何提高精度?


主元消元法

假设现在有个数\(p\),还有两个数\(10^5,10^{-5}\)

那么\(p\)除以哪个数,分到的小数位数(精度)越高呢?

显然,是\(10^5\)。那么根据我们推导的结论,除数绝对值越大越好

然后我们仔细观察朴素消元的代码

会惊奇的发现只有一行对精度会有影响:


  1. double k=c[j][i]/c[i][i];

根据我们刚刚推导的结论,\(c[i][i]\)绝对值越大,精度越高

因此,我们只需把朴素代码中的找不为\(0\)的数改成找绝对值最大的数即可


  1. void gauss()
  2. {
  3. for(int i=1;i<=n;i++)
  4. {
  5. for(int j=i+1;j<=n;j++)
  6. {
  7. if(fabs(c[j][i])>fabs(c[i][i]))//找最大值
  8. {
  9. for(int k=1;k<=n+1;k++)
  10. {
  11. swap(c[j][k],c[i][k]);
  12. }
  13. }
  14. }
  15. if(fabs(c[i][i])<=1e-8)continue;//若全为0,不必继续消
  16. for(int j=i+1;j<=n;j++)
  17. {
  18. double t=c[j][i]/c[i][i];
  19. for(int k=1;k<=n+1;k++)
  20. {
  21. c[j][k]=c[j][k]-t*c[i][k];
  22. }
  23. }
  24. }
  25. }

这样我们就大大提高了算法的精度

还剩最后一个问题:如何判断有多组解的情况?

只需判断某一行消完后是否全为\(0\)即可(自己稍微想想即可)

详见完整代码:

  1. #include<iostream>
  2. #include<cstdio>
  3. #include<algorithm>
  4. #include<cstring>
  5. #include<cmath>
  6. using namespace std;
  7. const int N=20;
  8. int n;
  9. double b[N][N],c[N][N],res[N];
  10. void gauss()
  11. {
  12. for(int i=1;i<=n;i++)
  13. {
  14. for(int j=i+1;j<=n;j++)
  15. {
  16. if(fabs(c[j][i])>fabs(c[i][i]))
  17. {
  18. for(int k=1;k<=n+1;k++)
  19. {
  20. swap(c[j][k],c[i][k]);
  21. }
  22. }
  23. }
  24. if(fabs(c[i][i])<=1e-8)continue;
  25. for(int j=i+1;j<=n;j++)
  26. {
  27. double t=c[j][i]/c[i][i];
  28. for(int k=1;k<=n+1;k++)
  29. {
  30. c[j][k]=c[j][k]-t*c[i][k];
  31. }
  32. }
  33. }
  34. }
  35. int main()
  36. {
  37. scanf("%d",&n);
  38. for(int a=1;a<=n;a++)
  39. for(int b=1;b<=n+1;b++)
  40. {
  41. scanf("%lf",&c[a][b]);
  42. }
  43. guass();
  44. for(int i=1;i<=n;i++)
  45. {
  46. bool fail=true;
  47. for(int j=1;j<=n+1;j++)
  48. {
  49. if(c[i][j])
  50. {
  51. fail=false;
  52. break;
  53. }
  54. }
  55. if(fail)//若某行的系数全为0,则说明无唯一解
  56. {
  57. puts("No Solution");
  58. return 0;
  59. }
  60. }
  61. for(int i=n;i>=1;i--)
  62. {
  63. double t=0;
  64. for(int j=i+1;j<=n;j++)
  65. {
  66. t=t+res[j]*c[i][j];
  67. }
  68. res[i]=(c[i][n+1]-t)/c[i][i];
  69. }
  70. for(int i=1;i<=n;i++)printf("%.2lf\n",res[i]);
  71. return 0;
  72. }

Luogu P3389 高斯消元的更多相关文章

  1. 【Luogu】P3389高斯消元模板(矩阵高斯消元)

    题目链接 高斯消元其实是个大模拟qwq 所以就着代码食用 首先我们读入 ;i<=n;++i) ;j<=n+;++j) scanf("%lf",&s[i][j]) ...

  2. 洛谷P3389 高斯消元 / 高斯消元+线性基学习笔记

    高斯消元 其实开始只是想搞下线性基,,,后来发现线性基和高斯消元的关系挺密切就一块儿在这儿写了好了QwQ 先港高斯消元趴? 这个算法并不难理解啊?就会矩阵运算就过去了鸭,,, 算了都专门为此写个题解还 ...

  3. luogu P2962 [USACO09NOV]灯Lights 高斯消元

    目录 题目链接 题解 题目链接 luogu P2962 [USACO09NOV]灯Lights 题解 可以折半搜索 map合并 复杂度 2^(n / 2)*logn 高斯消元后得到每个点的翻转状态 爆 ...

  4. 【Luogu】P3211XOR和路径(高斯消元)

    题目链接 唉我个ZZ…… 首先考虑到异或是可以每一位分开算的 好的以后再碰见位运算题我一定先往按位开车上想 然后设f[i]为从i点出发到终点是1的概率 高斯消元解方程组即可. #include< ...

  5. 【Luogu】P4035球形空间产生器(高斯消元)

    题目链接 水比题,把圆方程展开减一下把平方都减掉半径的平方也减掉,高斯消元即可. 然后我只输出两位小数,爆了两次零.我好菜啊. #include<cstdio> #include<c ...

  6. 【Luogu】P2447外星千足虫(高斯消元)

    题目链接 高斯消元解%2意义下的方程,Bitset优化一下. 在消的过程中就能顺便把有解的第一问求出来,记录一下访问过的最大行. #include<cstdio> #include< ...

  7. 【Luogu】P3317重建(高斯消元+矩阵树定理)

    题目链接 因为这个专门跑去学了矩阵树定理和高斯消元qwq 不过不是很懂.所以这里只放题解 玫葵之蝶的题解 某未知dalao的矩阵树定理 代码 #include<cstdio> #inclu ...

  8. Luogu P5027 【Barracuda】(高斯消元)

    祭一下第一道独立做出来的高斯消元(虽然在各大佬看来都是水题...) 首先这道题给了你n+1个一次方程,n个未知数 其中有一个方程是错误的 求解在合法的前提下最大的未知数是多少... 显然高斯消元... ...

  9. Luogu P2447 [SDOI2010]外星千足虫 高斯消元

    链接 给出的条件是异或类型的方程,可以直接用bitset优化高斯消元. 至于求K,在高斯消元时记录用到的最大的方程的编号即可. 代码: // luogu-judger-enable-o2 #inclu ...

随机推荐

  1. 【LeetCode】57. Insert Interval [Interval 系列]

    LeetCode中,有很多关于一组interval的问题.大体可分为两类: 1.查看是否有区间重叠: 2.合并重叠区间;  3.插入新的区间: 4. 基于interval的其他问题 [ 做题通用的关键 ...

  2. Matlab学习-(4)

    1. 函数 1.1 原始方法 之前我调用函数的方法是,首先写好函数文件,然后保存,然后在主函数中调用.这种方法的不足在于会导致你的工作目录的文件太多,从而导致很乱.在网上找了一些解决方法. 1.2 本 ...

  3. 最新超详细VMware虚拟机安装完整教程

    一.基础介绍 VMWare虚拟机软件是一个“虚拟PC”软件,它使你可以在一台机器上同时运行二个或更多Windows.DOS.LINUX系统.与“多启动”系统相比,VMWare采用了完全不同的概念.多启 ...

  4. 好用的mitmproxy代理抓包

    安装证书 浏览器输入 `mitm.it` 下载证书有时候打不开,可能是起的服务卡死了,回车下命令行,再再网页刷新下载证书就可以了. mitmweb Chrome浏览器代理设置 打开的话,记得保存点一下 ...

  5. 一篇文章掌握网页解析神器——xpath

    学爬虫不会xpath解析数据? 今天老师带你一堂课带你从零开始精通xpath,从此轻松提取网页信息. 我们在爬虫的过程中,经常会遇到html字符串数据,很多我们需要的数据不是作为标签的文本就是作标签的 ...

  6. 使用 Python 控制自己的电脑和键盘是一种什么样的体验?python学习的正确姿势

    可能有时候你需要在电脑做一些重复的点击或者提交表单等操作,如果能通过 Python 预先写好相关的操作指令,让它帮你操作,然后你自己爱干嘛干嘛去,有点 “按键精灵” 的意思,是不是感觉有点爽呢? 那么 ...

  7. 用scanf、printf输入输出string型字符串

    c语言里是没有string型的,string在c++里面.有的时候在c++里要用scanf.printf输入输出string型字符串,这是可以实现的,不过要做一点处理. 具体操作看代码: #inclu ...

  8. 定期清理nohup.out

    事件背景 服务应用weblogic通过nohup启动. nohup的使用全部都在weblogic域中的bin目录下 但是没有做定期nohup.out的清理 导致核心服务的日志过大,在出现问题时候难以打 ...

  9. ansible的剧本play(四)

    aaarticlea/png;base64,iVBORw0KGgoAAAANSUhEUgAAA68AAAETCAYAAADZDzDOAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjw

  10. nCOV 数据简要分析 (0326)

    nCOV 数据简要分析 (0326) matlabdatacov 简介 碰巧看到了数据上传, 正在跑数据的我想着要不拟合一下看看, 然后, 就做了两个小时, 这里做一个简单的记录过程, 后续可能做在线 ...