高斯消元专题

高斯消元法可用来找出下列方程组的解或其解的限制:捕获1
这个算法的原理是:
首先,要将L1以下的等式中的x消除,然后再将L2以下的等式中的y消除。这样可使整个方程组变成一个三角形似的格式。之后再将已得出的答案一个个地代入已被简化的等式中的未知数中,就可求出其余的答案了。
捕获2
第二步,就是由尾至头地将已知的答案代入其他等式中的未知数。第一个答案就是:捕获3
然后就可以将z代入L2中,立即就可得出第二个答案:捕获4
之后,将z和y代入L1之中,最后一个答案就出来了:捕获5
就是这样,这个方程组就被高斯消元法解决了

下面是n元线性方程组的一般形式:
捕获6
我们可以把它表示为增广矩阵的形式:
捕获7
然后就可以用高斯消元法在计算机上求解方程组了

对于刚才的例子,我们把它写成增广矩阵的形式:
捕获8

跟着以上的方法来运算,这个矩阵可以转变为以下的样子:
捕获9
这矩阵叫做“行梯阵式”。

最后,可以利用同样的算法产生以下的矩阵,便可把所得出的解或其限制简明地表示出来:
捕获10
最后这矩阵叫做“简化行梯阵式”,亦是高斯-约当消元法指定的步骤。

自由变元(有效的方程个数-变量数):
例子:x+y+z=1,这个方程是有无数解的,但是自由变元只有两个,但是每个变量都是无法确定的,只有当把两个自由变元的值确定了,这个方程便有了唯一解。

模板讲解:

普通版
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
constint MAXN=50; int a[MAXN][MAXN]; //增广矩阵
int x[MAXN]; //解集 boolfree_x[MAXN]; //标记是否是不确定的变元
inlineintgcd(inta, int b) {
     int t;
     while (b!=0) {
         t=b;
         b=a%b;
         a=t;
     }
     return a;
}
inlineint lcm(inta, int b) {
     return a/gcd(a,b)*b; //先除后乘防溢出 }
  // 高斯消元法解方程组(Gauss-Jordan elimination).(-2表示有浮点数解,但无整数解,
//-1表示无解,0表示唯一解,大于0表示无穷解,并返回自由变元的个数)
//有equ个方程,var个变元。增广矩阵行数为equ,分别为0到equ-1,列数为var+1,分别为0到var.
int Gauss(intequ,intvar) {
     inti,j,k;
     intmax_r; // 当前这列绝对值最大的行.     int col; //当前处理的列     intta,tb;
     int LCM;
     int temp;
     intfree_x_num;
     intfree_index;
     for (inti=0; i<=var; i++) {
         x[i]=0;
         free_x[i]= true ;
     }
     //转换为阶梯阵.     col=0; // 当前处理的列     for (k = 0; k <equ&& col <var; k++,col++) {
         // 枚举当前处理的行.
// 找到该col列元素绝对值最大的那行与第k行交换.(为了在除法时减小误差)         max_r=k;
         for (i=k+1; i<equ; i++) {
             if ( abs (a[i][col])> abs (a[max_r][col])) max_r=i;
         }
         if (max_r!=k) {
             // 与第k行交换.             for (j=k; j<var+1; j++) swap(a[k][j],a[max_r][j]);
         }
         if (a[k][col]==0) {
             // 说明该col列第k行以下全是0了,则处理当前行的下一列.             k--;
             continue ;
         }
         for (i=k+1; i<equ; i++) {
             // 枚举要删去的行.             if (a[i][col]!=0) {
                 LCM = lcm( abs (a[i][col]), abs (a[k][col]));
                 ta = LCM/ abs (a[i][col]);
                 tb = LCM/ abs (a[k][col]);
                 if (a[i][col]*a[k][col]<0)tb=-tb; //异号的情况是相加                 for (j=col; j<var+1; j++) {
                     a[i][j] = a[i][j]*ta-a[k][j]*tb;
                 }
             }
         }
     }
  
     // 1. 无解的情况: 化简的增广阵中存在(0, 0, ..., a)这样的行(a != 0).     for (i = k; i<equ; i++) {
         if (a[i][col] != 0) return -1;
     }
     // 2. 无穷解的情况: 在var * (var + 1)的增广阵中出现(0, 0, ..., 0)这样的行,即说明没有形成严格的上三角阵.     // 且出现的行数即为自由变元的个数.     // 对于无穷解来说,如果要判断哪些是自由变元,那么初等行变换中的交换就会影响,则要记录交换.     if (k <var) {
         // 首先,自由变元有var - k个,即不确定的变元至少有var - k个.         for (i = k - 1; i>= 0; i--) {
             // 第i行一定不会是(0, 0, ..., 0)的情况,因为这样的行是在第k行到第equ行.             // 同样,第i行一定不会是(0, 0, ..., a), a != 0的情况,这样的无解的.             free_x_num = 0; // 用于判断该行中的不确定的变元的个数,如果超过1个,则无法求解,它们仍然为不确定的变元.             for (j = 0; j <var; j++) {
                 if (a[i][j] != 0 &&free_x[j]) free_x_num++, free_index = j;
             }
             if (free_x_num> 1) continue ; // 无法求解出确定的变元.             // 说明就只有一个不确定的变元free_index,那么可以求解出该变元,且该变元是确定的.             temp = a[i][var];
             for (j = 0; j <var; j++) {
                 if (a[i][j] != 0 && j != free_index) temp -= a[i][j] * x[j];
             }
             x[free_index] = temp / a[i][free_index]; // 求出该变元.             free_x[free_index] = 0; // 该变元是确定的.         }
         return var - k; // 自由变元有var - k个.     }
     // 3. 唯一解的情况: 在var * (var + 1)的增广阵中形成严格的上三角阵.     // 计算出Xn-1, Xn-2 ... X0.     for (i = var - 1; i>= 0; i--) {
         temp = a[i][var];
         for (j = i + 1; j <var; j++) {
             if (a[i][j] != 0) temp -= a[i][j] * x[j];
         }
         if (temp % a[i][i] != 0) return -2; // 说明有浮点数解,但无整数解.         x[i] = temp / a[i][i];
     }
     return 0;
}
解浮点数方程
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
double a[MAXN][MAXN],x[MAXN]; //方程的左边的矩阵存在a中和等式右边的值存在x中,求解之后x存的就是结果 intequ,var; //方程数和未知数个数
/*
*返回0表示无解,1表示有解
*/ int Gauss() {
     inti,j,k,col,max_r;
     for (k=0,col=0; k<equ&&col<var; k++,col++) {
         max_r=k;
         for (i=k+1; i<equ; i++)
             if ( fabs (a[i][col])> fabs (a[max_r][col]))
                 max_r=i;
         if ( fabs (a[max_r][col]) <eps) return 0;
         if (k!=max_r) {
             for (j=col; j<var; j++)
                 swap(a[k][j],a[max_r][j]);
             swap(x[k],x[max_r]);
         }
         x[k]/=a[k][col];
         for (j=col+1; j<var; j++)a[k][j]/=a[k][col];
         a[k][col]=1;
         for (i=0; i<equ; i++)
             if (i!=k) {
                 x[i]-=x[k]*a[i][k];
                 for (j=col+1; j<var; j++)a[i][j]-=a[k][j]*a[i][col];
                 a[i][col]=0;
             }
     }
     return 1;
}
对2取模的01方程组
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
constint MAXN = 40; //有equ个方程,var个变元。增广矩阵行数为equ,列数为var+1,分别为0到var intequ,var; int a[MAXN][MAXN]; //增广矩阵
int x[MAXN]; //解集 intfree_x[MAXN]; //用来存储自由变元(多解枚举自由变元可以使用) intfree_num; //自由变元的个数 //返回值为-1表示无解,为0是唯一解,否则返回自由变元个数
int Gauss() {
     intmax_r,col,k;
     free_num = 0;
     for (k = 0, col = 0 ; k <equ&& col <var ; k++, col++) {
         max_r = k;
         for (inti = k+1; i<equ; i++) {
             if ( abs (a[i][col]) > abs (a[max_r][col]))
                 max_r = i;
         }
         if (a[max_r][col] == 0) {
             k--;
             free_x[free_num++] = col; //这个是自由变元             continue ;
         }
         if (max_r != k) {
             for ( int j = col; j < var+1; j++)
                 swap(a[k][j],a[max_r][j]);
         }
         for (inti = k+1; i<equ; i++) {
             if (a[i][col] != 0) {
                 for ( int j = col; j < var+1; j++)
                     a[i][j] ^= a[k][j];
             }
         }
     }
     for (inti = k; i<equ; i++)
         if (a[i][col] != 0)
             return -1; //无解     if (k <var) return var-k; //自由变元个数     //唯一解,回代     for (inti = var-1; i>= 0; i--) {
         x[i] = a[i][var];
         for ( int j = i+1; j <var; j++)
             x[i] ^= (a[i][j] && x[j]);
     }
     return 0;
}

推荐专题练习:hust
Click here!!!

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值