高斯消元 模板

相关博客

https://blog.csdn.net/cheneyshark/article/details/78735987

https://blog.csdn.net/cheneyshark/article/details/78751550

https://blog.csdn.net/pengwill97/article/details/77200372

https://www.cnblogs.com/Dumblidor/p/5751579.html

http://www.cnblogs.com/kuangbin/archive/2012/09/01/2667044.html

时间复杂度  O(n^3)

  1 #include<stdio.h>
  2 #include<algorithm>
  3 #include<iostream>
  4 #include<string.h>
  5 #include<math.h>
  6 using namespace std;
  7 const int MAXN=50;
  8 int a[MAXN][MAXN];//增广矩阵
  9 int x[MAXN];//解集
 10 bool free_x[MAXN];//标记是否是不确定的变元
 11 inline int gcd(int a,int b){int t;while(b!=0){t=b;b=a%b;a=t;}return a;}
 12 inline int lcm(int a,int b){return a/gcd(a,b)*b;}//先除后乘防溢出
 13 
 14 /*====================================================================================
 15 高斯消元法解方程组(Gauss-Jordan elimination).
 16     ---1>   -2表示有浮点数解,但无整数解
 17     ---2>   -1表示无解
 18     ---3>   0表示唯一解
 19     ---4>   大于0表示无穷解,并返回自由变元的个数
 20 =====================================================================================
 21 有equ个方程,var个变元。
 22 
 23 增广矩阵 行数为equ,   分别为0到equ-1.
 24          列数为var+1, 分别为0到var.
 25 =====================================================================================*/
 26 int Gauss(int equ,int var)
 27 {
 28     int i,j,k;
 29     int max_r;// 当前这列绝对值最大的行.
 30     int col;//当前处理的列
 31     int ta,tb;
 32     int LCM;
 33     int temp;
 34     int free_x_num;
 35     int free_index;
 36 
 37     for(int i=0; i<=var; i++)
 38     {
 39         x[i]=0;
 40         free_x[i]=true;
 41     }
 42 
 43     //转换为阶梯阵.
 44     col=0; // 当前处理的列
 45     for(k = 0; k < equ && col < var; k++,col++)
 46     {
 47         // 枚举当前处理的行.
 48 // 找到该col列元素绝对值最大的那行与第k行交换.(为了在除法时减小误差)
 49         max_r=k;
 50         for(i=k+1; i<equ; i++)
 51         {
 52             if(abs(a[i][col])>abs(a[max_r][col])) max_r=i;
 53         }
 54         if(max_r!=k)
 55         {
 56             // 与第k行交换.
 57             for(j=k; j<var+1; j++) swap(a[k][j],a[max_r][j]);
 58         }
 59         if(a[k][col]==0)
 60         {
 61             // 说明该col列第k行以下全是0了,则处理当前行的下一列.
 62             k--;
 63             continue;
 64         }
 65         for(i=k+1; i<equ; i++)
 66         {
 67             // 枚举要删去的行.
 68             if(a[i][col]!=0)
 69             {
 70                 LCM = lcm(abs(a[i][col]),abs(a[k][col]));
 71                 ta = LCM/abs(a[i][col]);
 72                 tb = LCM/abs(a[k][col]);
 73                 if(a[i][col]*a[k][col]<0)tb=-tb;    //异号的情况是相加
 74                 for(j=col; j<var+1; j++)
 75                 {
 76                     a[i][j] = a[i][j]*ta-a[k][j]*tb;
 77                 }
 78             }
 79         }
 80     }
 81     // 1. 无解的情况: 化简的增广阵中存在(0, 0, ..., a)这样的行(a != 0).
 82     for (i = k; i < equ; i++)
 83     {
 84         // 对于无穷解来说,如果要判断哪些是自由变元,那么初等行变换中的交换就会影响,则要记录交换.
 85         if (a[i][col] != 0) return -1;
 86     }
 87     // 2. 无穷解的情况: 在var * (var + 1)的增广阵中出现(0, 0, ..., 0)这样的行,即说明没有形成严格的上三角阵.
 88     // 且出现的行数即为自由变元的个数.
 89     if (k < var)
 90     {
 91         // 首先,自由变元有var - k个,即不确定的变元至少有var - k个.
 92         for (i = k - 1; i >= 0; i--)
 93         {
 94             // 第i行一定不会是(0, 0, ..., 0)的情况,因为这样的行是在第k行到第equ行.
 95             // 同样,第i行一定不会是(0, 0, ..., a), a != 0的情况,这样的无解的.
 96             free_x_num = 0; // 用于判断该行中的不确定的变元的个数,如果超过1个,则无法求解,它们仍然为不确定的变元.
 97             for (j = 0; j < var; j++)
 98             {
 99                 if (a[i][j] != 0 && free_x[j]) free_x_num++, free_index = j;
100             }
101             if (free_x_num > 1) continue; // 无法求解出确定的变元.
102             // 说明就只有一个不确定的变元free_index,那么可以求解出该变元,且该变元是确定的.
103             temp = a[i][var];
104             for (j = 0; j < var; j++)
105             {
106                 if (a[i][j] != 0 && j != free_index) temp -= a[i][j] * x[j];
107             }
108             x[free_index] = temp / a[i][free_index]; // 求出该变元.
109             free_x[free_index] = 0; // 该变元是确定的.
110         }
111         return var - k; // 自由变元有var - k个.
112     }
113     // 3. 唯一解的情况: 在var * (var + 1)的增广阵中形成严格的上三角阵.
114     // 计算出Xn-1, Xn-2 ... X0.
115     for (i = var - 1; i >= 0; i--)
116     {
117         temp = a[i][var];
118         for (j = i + 1; j < var; j++)
119         {
120             if (a[i][j] != 0) temp -= a[i][j] * x[j];    //--因为x[i]存的是temp/a[i][i]的值,即是a[i][i]=1时x[i]对应的值
121         }
122         if (temp % a[i][i] != 0) return -2; // 说明有浮点数解,但无整数解.
123         x[i] = temp / a[i][i];
124     }
125     return 0;
126 }
127 int main(void)
128 {
129     int i, j;
130     int equ,var;
131     while(scanf("%d %d", &equ,&var)!= EOF)
132     {
133         memset(a, 0, sizeof(a));
134         for (i = 0; i < equ; i++)
135         {
136             for (j = 0; j < var + 1; j++)
137             {
138                 scanf("%d", &a[i][j]);
139             }
140         }
141         int free_num = Gauss(equ,var);
142         if (free_num == -1)
143             printf("无解!\n");
144         else if (free_num == -2)
145             printf("有浮点数解,无整数解!\n");
146         else if (free_num > 0)
147         {
148             //printf("无穷多解! 自由变元个数为%d\n", free_num);
149             for (i = 0; i < var; i++)
150             {
151                 if (free_x[i]) printf("x%d 是不确定的\n", i + 1);
152                 else printf("x%d: %d\n", i + 1, x[i]);
153             }
154         }
155         else      //free_num==0 唯一解
156         {
157             for (i = 0; i < var; i++)
158             {
159                 printf("x%d: %d\n", i + 1, x[i]);
160             }
161         }
162         printf("\n");
163     }
164     return 0;
165 }

 

posted @ 2018-08-22 18:43  灬从此以后灬  阅读(159)  评论(0编辑  收藏  举报