高斯消元的模板:
#include<stdio.h> #include<algorithm> #include<iostream> #include<string.h> #include<math.h> using namespace std; const int MAXN=50; int a[MAXN][MAXN];//增广矩阵 int x[MAXN];//解集 bool free_x[MAXN];//不确定的变元 int equ,var,free_num; void Debug() { int i, j; for (i = 0; i < equ; i++) { for (j = 0; j < var + 1; j++) { cout << a[i][j] << " "; } cout << endl; } cout << endl; } int gcd(int a,int b) { return b?gcd(b,a%b):a; } int lcm(int a,int b) { return a/gcd(a,b)*b; } // 高斯消元法解方程组(free_num=-2表示有浮点数解,但无整数解, //-1表示无解,0表示唯一解,大于0表示无穷解,并返回自由变元的个数) //有equ个方程,var个变元。增广矩阵行数为equ,分别为0到equ-1,列数为var+1,分别为0到var. int Gauss(int equ,int var) { int i,j,k; int max_r; int col;//当前处理的列 int ta,tb; int LCM; int temp; int free_x_num; int free_index; 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) { for(j=k;j<var+1;j++) swap(a[k][j],a[max_r][j]); } //Debug(); 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; } } } //Debug(); } // 1. 无解的情况: 化简的增广阵中存在(0, 0, ..., a)这样的行(a != 0). for (i = k; i < equ; i++) { if (a[i][col] != 0) return -1; } if (k < var) { //自由变元,不确定的变元至少有var - k个. for (i = k - 1; i >= 0; i--) { 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; 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个. } 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; } void in(){ memset(a, 0, sizeof(a)); memset(x,0,sizeof(x)); memset(free_x,1,sizeof(free_x)); int i,j; for (i = 0; i < equ; i++) { for (j = 0; j < var + 1; j++)scanf("%d", &a[i][j]); } } void out(){ int i,j; if (free_num == -1) printf("no solutions!\n"); else if (free_num == -2) printf("here are double but not Integer solutions!\n"); else if (free_num > 0) { printf("here are many solutions and var number is %d\n", free_num); for (i = 0; i < var; i++) { if (free_x[i]) printf("x%d is not certain\n", i + 1); else printf("x%d: %d\n", i + 1, x[i]); } } else for (i = 0; i < var; i++)printf("x%d: %d\n", i + 1, x[i]); printf("\n"); } int main(void) { freopen("cin.txt", "r", stdin); int i, j; while (scanf("%d %d", &equ, &var) != EOF) { in(); free_num = Gauss(equ,var); out(); } return 0; }测试用例:
程序的结果:
x1: 2
x2: 3
x3: -1
here are many solutions and var number is 1
x1: 2
x2: -3
x3 is not certain
here are double but not Integer solutions!
no solutions!
中间的过程(以:
3 3
2 1 -1 8
-3 -1 2 -11
-2 1 2 -3
为例):
-3 -1 2 -11
2 1 -1 8
-2 1 2 -3
-3 -1 2 -11
0 1 1 2
0 5 2 13
-3 -1 2 -11
0 5 2 13
0 1 1 2
-3 -1 2 -11
0 5 2 13
0 0 3 -3
-3 -1 2 -11
0 5 2 13
0 0 3 -3
-3 -1 2 -11
0 5 2 13
0 0 3 -3
x1: 2
x2: 3
x3: -1
#include <cstdio> #include <iostream> #include <algorithm> #include <cstring> using namespace std; const int N=105; int gcd(int a,int b){ return b==0?a:gcd(b,a%b); } // a[][]:增广矩阵 n: 方程数 m:变量数 void Gauss(int a[N][N],int n,int m,int &r,int &c){ for(r=0,c=0;r<n&&c<m;r++,c++){ int maxi=r; for(int i=r+1;i<n;i++){ if(abs(a[i][c])>abs(a[maxi][c])) maxi=i; } if(maxi!=r){ for(int j=r;j<m+1;j++){ // 1 swap(a[r][j],a[maxi][j]); } } if(a[r][c]==0){ r--; continue; } for(int i=r+1;i<n;i++){ if(a[i][c]!=0){ int x=abs(a[i][c]); int y=abs(a[r][c]); int lcm=x/gcd(x,y)*y; int tx=lcm/x; int ty=lcm/y; if(a[i][c]*a[r][c]<0) ty=-ty; for(int j=c;j<m+1;j++){ a[i][j]=a[i][j]*tx-a[r][j]*ty; } } } } } // -2 没有整数解 -1:无解 0: 唯一解 m-r:(自由变元个数)无穷多个解 int reback(int a[][N],int n,int m,int r,int c,int x[],bool tag[]){ for(int i=r;i<n;i++) if(a[i][c]!=0) return -1; if(r<m){ memset(tag,0,sizeof(tag)); for(int i=r-1;i>=0;i--){ int dex=0; int cnt=0; for(int j=0;j<m;j++){ if(a[i][j]!=0&&tag[j]==0){ cnt++; dex=j; } } if(cnt>1) continue; int t=a[i][m]; for(int j=0;j<m;j++){ if(a[i][j]!=0&&j!=dex){ t-=a[i][j]*x[j]; } } x[dex]=t/a[i][dex]; tag[dex]=1; } return m-r; } for(int i=r-1;i>=0;i--){ int t=a[i][c]; for(int j=i+1;j<c;j++) t-=a[i][j]*x[j]; if(t%a[i][i]!=0) return -2; x[i]=t/a[i][i]; } return 0; } int a[N][N]; int x[N]; bool tag[N]; int main(){ //freopen("cin.txt","r",stdin); int n,m; while(cin>>n>>m){ for(int i=0;i<n;i++){ for(int j=0;j<m+1;j++){ scanf("%d",&a[i][j]); } } int r,c; Gauss(a,n,m,r,c); reback(a,n,m,r,c,x,tag); for(int i=0;i<n;i++){ for(int j=0;j<m+1;j++) cout<<a[i][j]<<" "; cout<<endl; } for(int i=0;i<r;i++) cout<<x[i]<<" "; cout<<endl; } return 0; }
#include <cstdio> #include <iostream> #include <algorithm> #include <cstring> #include <cmath> using namespace std; const int N=105; const double eps=1e-7; int myCmp(double a,double b){ if(fabs(a-b)<eps) return 0; return (a>b)-(a<b); } double myMod(double a,double m){ while(myCmp(a,m)>=0) a-=m; while(myCmp(a,0)<0) a+=m; return a; } double gcd(double a,double b){ return myCmp(b,0)==0?a:gcd(b,myMod(a,b)); } // a[][]:增广矩阵 n: 方程数 m:变量数 void Gauss(double a[N][N],int n,int m,int &r,int &c){ for(r=0,c=0;r<n&&c<m;r++,c++){ int maxi=r; for(int i=r+1;i<n;i++){ if(myCmp(abs(a[i][c]),abs(a[maxi][c]))>0) maxi=i; } if(maxi!=r){ for(int j=r;j<m+1;j++){ // 1 swap(a[r][j],a[maxi][j]); } } if(myCmp(a[r][c],0)==0){ r--; continue; } for(int i=r+1;i<n;i++){ if(myCmp(a[i][c],0)!=0){ double x=fabs(a[i][c]); double y=fabs(a[r][c]); double lcm=x*y/gcd(x,y); double tx=lcm/x; double ty=lcm/y; if(a[i][c]*a[r][c]<-eps) ty=-ty; for(int j=c;j<m+1;j++){ a[i][j]=a[i][j]*tx-a[r][j]*ty; } } } } } // -1:无解 0: 唯一解 m-r:(自由变元个数)无穷多个解 int reback(double a[][N],int n,int m,int r,int c,double x[],bool tag[]){ for(int i=r;i<n;i++) if(myCmp(a[i][c],0)!=0) return -1; if(r<m){ memset(tag,0,sizeof(tag)); for(int i=r-1;i>=0;i--){ int dex=0; int cnt=0; for(int j=0;j<m;j++){ if(myCmp(a[i][j],0)!=0&&tag[j]==0){ cnt++; dex=j; } } if(cnt>1) continue; double t=a[i][m]; for(int j=0;j<m;j++){ if(myCmp(a[i][j],0)!=0&&j!=dex){ t-=a[i][j]*x[j]; } } x[dex]=t/a[i][dex]; tag[dex]=1; } return m-r; } for(int i=r-1;i>=0;i--){ double t=a[i][c]; for(int j=i+1;j<c;j++) t-=a[i][j]*x[j]; //if(myCmp(myMod(t,a[i][i]),0)!=0) return -2; x[i]=t/a[i][i]; } return 0; } double a[N][N]; double x[N]; bool tag[N]; int main(){ freopen("cin.txt","r",stdin); int n,m; while(cin>>n>>m){ for(int i=0;i<n;i++){ for(int j=0;j<m+1;j++){ scanf("%lf",&a[i][j]); } } int r,c; Gauss(a,n,m,r,c); reback(a,n,m,r,c,x,tag); /*for(int i=0;i<n;i++){ for(int j=0;j<m+1;j++) cout<<a[i][j]<<" "; cout<<endl; }*/ for(int i=0;i<r;i++) { printf("%.15lf ",x[i]); } cout<<endl; } return 0; }
用mathematica计算:
In[1]:= Solve[{0.001*x1 + 2 x2 == 1, 3*x1 + 5*x2 == 2}, {x1, x2}] Out[1]= {{x1 -> -0.166806, x2 -> 0.500083}} In[2]:= Solve[{0.0000000000000001*x1 + 20000*x2 == 10000, 300*x1 + 500*x2 == 2000}, {x1, x2}] Out[2]= {{x1 -> 5.83333, x2 -> 0.5}} In[3]:= Solve[{0.0000000000000000001*x1 + 20000*x2 == 10000, 30000000000000*x1 + 500*x2 == 2000}, {x1, x2}] Out[3]= {{x1 -> 5.83333*10^-11, x2 -> 0.5}} 高斯运算结果: -0.166805671392827 0.500083402835696 5.833333333333333 0.500000000000000 0.000000000058333 0.500000000000000 Process returned 0 (0x0) execution time : 0.375 s Press any key to continue.