zoukankan      html  css  js  c++  java
  • 高斯消元 模板

    传送门

    给定一个n元一次方程组求解。

    首先我们思考一下,自己解普通的二元一次方程组的时候是怎么解的?

    我们肯定是要先用一个变量表示另一个变量,换句话说,先进行消元,然后转变为一元一次方程求解。

    我们一般有两种做法,加减消元或者带入消元。(这里以二元一次方程组为例,多元的也一样)

    但是我们在使用程序计算的时候需要一种有规律可寻的算法,所以我们选择在开始的时候进行加减消元,返回的时候进行带入消元(把计算出来的结果带回去再计算)

    首先,我们获得了一个n元一次方程组。之后我们要消除一个元,我们会怎么做?先把这个式子的第一个元的系数变为1,再把这个式子所有未知数前面的系数都乘以一个实数,使得在和其他式子计算的时候把这个元的系数消为0。(脑补一下做题时候的画面)之后再诸如此种操作去不断消元,直到最后获得一个一元一次方程,就可以轻松的计算出最后的得数。

    之后我们把这个得数回带到刚才的式子里面,就又可以解出一个得数(因为系数为1嘛),之后这样不断地返回就可以解出n元一次方程组的解。时间复杂度O(n^3)。

    注意因为我们只能使用double,所以必然会有精度误差(除非强大到全写高精度……那是不可能的),所以我们尽量每次用系数最大的一个去消其他的元,这样能尽量减小误差。我们来偷一位dalao的证明:

    这样高斯消元就结束了……(如果中间有不理解的直接想想自己平时解方程组怎么解就好了)

    看一下代码。

    #include<iostream>
    #include<cstdio>
    #include<cmath>
    #include<algorithm>
    #include<queue>
    #include<cstring>
    #include<utility>
    #include<map>
    #define pr pair<int,int>
    #define mp make_pair
    #define fi first
    #define sc second
    #define rep(i,a,n) for(int i = a;i <= n;i++)
    #define per(i,n,a) for(int i = n;i >= a;i--)
    #define enter putchar('
    ')
    using namespace std;
    typedef long long ll;
    const int M = 100005;
    const int N = 500005;
    const int INF = 1000000009;
    const double eps = 1e-7;
    int read()
    {
        int ans = 0,op = 1;
        char ch = getchar();
        while(ch < '0' || ch > '9')
        {
        if(ch == '-') op = -1;
        ch = getchar();
        }
        while(ch >='0' && ch <= '9')
        {
        ans *= 10;
        ans += ch - '0';
        ch = getchar();
        }
        return ans * op;
    }
    
    double g[105][105],ans[105];
    int n;
    
    int main()
    {
        n = read();
        rep(i,1,n)
        rep(j,1,n+1) scanf("%lf",&g[i][j]);
        rep(i,1,n)
        {
        int r = i;
        rep(j,i+1,n) if(fabs(g[r][i]) < fabs(g[j][i])) r = j;//找到当前系数最大的
        if(fabs(g[r][i]) < eps)//如果系数为0说明无解
        {
            printf("No Solution");
            return 0;
        }
        if(i != r) swap(g[i],g[r]);//把两行交换,这样就相当于我们每次都消去第一行,比较方便
        double div = g[i][i];//取这个系数
        rep(j,i,n+1) g[i][j] /= div;//把这行的每个系数都/div(相当于把当前要消的元的系数变为1)
        rep(j,i+1,n)
        {
            div = g[j][i];
            rep(k,i,n+1) g[j][k] -= g[i][k] * div;//对每一个式子进行消元(其中i肯定被消了,因为原来的式子里其系数为1)
        }
        }
        ans[n] = g[n][n+1];//得到最终结果
        per(i,n-1,1)//开始回带
        {
        ans[i] = g[i][n+1];//取上一次的答案
        rep(j,i+1,n) ans[i] -= g[i][j] * ans[j];//计算新的答案,就是这一行的值-前面已经算出来的变量×系数,不理解可以自己模拟一下
        }
        rep(i,1,n) printf("%.2lf
    ",ans[i]);//输出每个答案
        return 0;
    }
  • 相关阅读:
    Linux查看某个端口使用情况并kill
    CentOS 7.0关闭默认防火墙启用iptables防火墙
    Centos7配置JAVA_HOME
    Android Http请求方法汇总
    Android开发总结之 --- 定时,读写文件
    二维码,条形码
    SIM卡相关
    Eclipse快捷键
    easyui datagrid 表格不让选中(双层嵌套)
    easyui datagrid 三层嵌套
  • 原文地址:https://www.cnblogs.com/captain1/p/9686293.html
Copyright © 2011-2022 走看看