• 高斯消元法


    高斯消元问题通常用来对线性方程组的求解

    根据线性代数中所学,线性方程通常可表示成

    a[i][0]*x0 + a[i][1]*x1 +a [i][2]*x2 ... + a[i][n-1]*xn-1 = b[i]

    0<=i<n

    这样就可以得到一个由n个线性方程组成方程组

    我们通常将a[][]放入数组中的对应位置,b[] 作为一整列插入到a数组的最后一排

     

    不断通过对行进行操作

    比如 ri - k*rj , 用第i行的元素每一个都减去第j行对应列的元素的k倍,我们总是希望能够通过这个操作不断将矩阵朝着除去 b[]后的上三角

    矩阵化简,就是令下三角矩阵均为0

    那么就是不断从第一列开始不断将需要化简为0的项转化为0即可

    那么我们就可以利用回代的方法,先算出最后一项x,然后不断往前递推,在第i行得到x[i]

    当然这是最好的情况,解决线性方程组往往给的方程的数量和对应x的变量数量不一定相同

    我令方程数量为equ , 变量数量为 var , 那么如果equ < var 的时候必然是有解的

    因为至少有 var-equ+1个自由变量

    因为每一行都会解决至多一个自由变量,当然如果某一行和前面的一行 的系数都存在倍数关系 exp: ai = k*aj

    那么那一行其实效果是没有的,这个时候就一个自由变量都没有解决了

    另外如果在化简矩阵的过程中某一行出现了(0,0,0,0....,0,b[i])(b[i] != 0)的情况那么就说明是不存在解的

    所以对于我们来说,只要除去那些有相同效果的方程,剩下的方程组含有的方程为equ,那么

    自由变量的个数就是 var - equ + 1 , 当自由变量个数大于1的时候我们就可以认为是有无穷多个解的

    我们利用这个思想解决计算机上的问题时,可以套用如下模版:

      1 int gcd(int a , int b)
      2 {
      3     if(b == 0) return a;
      4     else return gcd(b , a%b);
      5 }
      6 
      7 int lcm(int a , int b)
      8 {
      9     return a/gcd(a , b)*b;//先除后乘防止溢出
     10 }
     11 
     12 inline int my_abs(int x)
     13 {
     14     return x>=0?x:-x;
     15 }
     16 
     17 inline void my_swap(int &a , int &b)
     18 {
     19     int tmp = a;
     20     a = b , b = tmp;
     21 }
     22 /*
     23 高斯消元解线性方程组的解
     24 返回-2表示有浮点数的解,但无整数解
     25 返回-1表示无解
     26 返回0表示唯一解
     27 大于0,表示无穷解,返回的是自由变元个数
     28 有equ个方程,var个变元。增广矩阵行数为equ,分别为0到equ-1,列数为var+1,分别为0到var
     29 总是考虑上三角部分,所以内部更新总是只更新了上三角部分
     30 */
     31 int gauss(int equ , int var)
     32 {
     33     int max_r; // 当前这列绝对值最大的行
     34     int col; // 当前处理的列
     35     int ta , tb , i , j , k;
     36     int Lcm , tmp , free_x_num , free_index;
     37 
     38     for(i=0 ; i<=var ; i++)
     39         x[i] = 0 , free_x[i] = true;
     40 
     41     //转化为阶梯形矩阵
     42     col = 0;//一开始处理到第0列
     43     for(k=0 ; k<equ && col < var; k++,col++){
     44     /*
     45     枚举当前处理的行
     46     找到该行col列元素绝对值最大的那行与第k行交换,
     47     这样进行除法运算的时候就可以避免小数除以大数了
     48     */
     49         max_r = k;
     50         for(i = k+1 ; i<equ ; i++)
     51             if(my_abs(a[i][col]) > my_abs(a[max_r][col]))
     52                 max_r = i;
     53         if(max_r != k){
     54             //交换两行的数据
     55             for(i=k ; i<var+1 ; i++)
     56                 my_swap(a[max_r][i] , a[k][i]);
     57         }
     58 
     59         if(a[k][col] == 0){
     60             //说明该col列第k行以下全是0了,则处理当前行的下一列
     61             k--;
     62             continue;
     63         }
     64 
     65         for(i=k+1 ; i<equ ; i++){
     66             //枚举要删去的行
     67             if(a[i][col] != 0 ){
     68                 Lcm = lcm(my_abs(a[i][col]) , my_abs(a[k][col]));
     69                 ta = Lcm / my_abs(a[i][col]);
     70                 tb = Lcm / my_abs(a[k][col]);
     71                 if(a[i][col] * a[k][col] < 0) tb = -tb;//异号相加
     72                 for(j = col ; j<var+1 ; j++)
     73                     a[i][j] = a[i][j]*ta - a[k][j]*tb ;
     74             }
     75         }
     76     }
     77 
     78     //1.无解的情况
     79     for(i=k ; i<equ ; i++){
     80         if(a[i][col] != 0) return -1;
     81     }
     82 
     83     //2.无穷解:在var*(var+1) 的增广阵中出现了(0,0,0....,0)这样的行,也即说明没有出现严格的上三角
     84     //出现这样情况的行数也就是自由变元的个数
     85     if(k < var){
     86         //首先初始化自由变元有var-k个,即不确定的变元至少有var-k个
     87         for(i=k-1 ; i>=0 ; i--){
     88             //第i行一定不会是(0,0,0,...,0)的情况,因为这样的行实在第k行到equ行
     89             //同样,第 i 行一定不会是(0,0 ... , a) , a != 0的情况
     90 
     91             free_x_num = 0;
     92             //free_x_num记录自由变元个数,如果超过1个,则解集无穷,无法求解.
     93 
     94             for(j=0 ; j<var ; j++){
     95                 if(a[i][j] != 0 && free_x[j]) free_x_num++ , free_index = j;
     96             }
     97 
     98             if(free_x_num > 1) continue; //无法求解出确定变元
     99 
    100             tmp = a[i][var];
    101             for(j=0 ; j<var ; j++)
    102                 if(a[i][j] != 0 && j != free_index)
    103                     tmp -= a[i][j]*x[j];
    104             x[free_index] = tmp / a[i][free_index];//求出该变元
    105             free_x[free_index] = false;//该变元确定
    106         }
    107         return var - k;//自由变元有var-k个
    108     }
    109 
    110     //唯一解的情况:在var*(var+1) 的增广矩阵中形成严格的上三角阵
    111     //计算x[n-1] , x[n-2] .... x[0] 回代计算,先得到后面的值,推到前面的值
    112     for(int i=var-1 ; i>=0 ; i--){
    113         tmp = a[i][var];
    114         for(int j=i+1 ; j<var ; j++){
    115             if(a[i][j] != 0 ) tmp -= a[i][j]*x[j];
    116         }
    117        // if(tmp % a[i][i] != 0) return -2; //说明浮点数存在,无整数解,但是有小数解
    118         x[i] = tmp / a[i][i];
    119     }
    120     return 0;
    121 }
  • 相关阅读:
    解决:oracle+myBatis ResultMap 类型为 map 时返回结果中存在 timestamp 时使用 jackson 转 json 报错
    jackson @ResponseBody 处理日期类型的字段
    spring 中 InitializingBean 接口使用理解
    idea 中如何生成类图
    阿里云centOS 重启后 重启应用步骤
    日期类型 通过JOSN.stringify 后时间倒退8小时问题
    centOS7 下 安装mysql8.x
    Linux下卸载mysql8.x版本
    服务器上 MySql 8.0.16创建远程连接账号、获取初始密码、修改密码、重启命令等
    vue中读取excel中数据
  • 原文地址:https://www.cnblogs.com/CSU3901130321/p/4239003.html
Copyright © 2020-2023  润新知