一.線性方程組求解定理
1.線性方程組有解判別定理 線性方程組
a11 x1 + a12 x2 + … + a1n x n = b1 ,
a21 x1 + a22 x2 + … + a2n x n = b2 ,
......................................................
as1 x1 + as2 x2 + … + asn x n = bs
有解的充分必要條件是 : 它的系數矩陣與增廣矩陣有相同的秩 .
2. 齊次線性方程組
a11 x1 + a12 x2 + … + a1n x n = 0 ,
a21 x1 + a22 x2 + … + a2n x n = 0 ,
......................................................
as1 x1 + as2 x2 + … + asn x n = 0
有非零解的充分必要條件是: 它的系數矩陣的秩 r 小於未知量個數 n .
齊次線性方程組求解一般步驟:
1.把系數矩陣通過初等變換,變換成階梯形矩陣.
2.判斷階梯形矩陣中非零行的個數秩(r),以及計算自由元個數m=n-r.
3.確定自由元位置,然后以次為它們賦值1,0...
4.求解出方程組的基礎解系.
5.用基礎解系表示出方程全解.
非齊次線性方程組求解,與齊次線性方程組求解過程基本一致,只需要再求出一個特解。
二.如何用C語言計算線性方程組的解
那么如何用算法求出線性方程組的解呢?
就是根據上面方程組求解一般步驟來的,
1.矩陣的初等變換(在上次行列式計算的基礎上,這個很好實現).
2.求出矩陣的秩/自由元個數,然后確定自由元的位置(我認為這是一個難點)
3.初始化自由元(1,0,..),計算變量,最終求出基礎解系
4.非齊次線性方程
4.1.先求出齊次線性方程組的基礎解系
4.2.再利用上面步驟求一個特解即可
1.矩陣的初等變換
//初等行變換 void primaryRowChange(int s, int n, double **array) { int i,j,k,ii,kk,flag; double temp; for(i=0,j=0;i<s-1;i++,j++)//s行,最外圍只需要變換s-1 { ii=i; //如果行的首元為0,向下查找一個不為0的,然后換行 if(*(*(array+i)+j) == 0) { flag=0; for(k=i+1;k<s;k++) { if(*(*(array+k)+j)!=0)//第k行與第i行交換 { for(kk=j;kk<n;kk++) { temp=*(*(array+k)+kk); *(*(array+k)+kk) = *(*(array+i)+kk); *(*(array+i)+kk) = temp; } flag =1; break; } } //判斷是交換成功,如果沒有成功,則i-- if(!flag) { i--; continue; } i--; j--; continue; } for(;ii<s-1;ii++) { if(*(*(array+ii+1)+j)==0) continue; temp =-*(*(array+ii+1)+j) / *(*(array+i)+j); for(k=j;k<n;k++) *(*(array+ii+1)+k) += *(*(array+i)+k) * temp; } } }
2.計算矩陣的秩
//計算矩陣的秩 int getRank(int s, int n, double **array) { int flag; int i,j,r=s; //判斷非零行個數 for(i=0;i<s;i++) { flag=0; for(j=0;j<n;j++) { if(*(*(array+i)+j)!=0 && (*(*(array+i)+j)>0.01 || *(*(array+i)+j) <-0.01))//排除很小數, { flag=1; break; } } if(!flag)//當前行全為零,則r為i; { r=i; break; } } return r; }
3.確定自由元位置
自由元確定需要考慮兩種情況:
1).系數梯形矩陣最后一行只有一個非零元素.
2) 系數梯形矩陣中某行的個數等於自由元的個數.
//獲取自由元信息 int* getFreeElement(int r, int n, double **array, int **matrixPrimary, double **matrixCalc) { int i,j,k,o,p,q; int m=n-1-r;//n-1: int *freeElement =(int*)malloc(m*sizeof(int)); j=-1;//判斷是否有為0的變量 q=0;//如果當前行非零個數與自由元個數相等,則標記為1,自由元選擇起始位置左移一位 for(i=r-1;i>=0;i--)//查找自由元,及位置為0的 { if(*(*(matrixPrimary+i)+1)==1)//說明第i行只有一個變量,如果是齊次方程它的解一定為0 { j=*(*(matrixPrimary+i)+0); for(k=0;k<r;k++) *(*(matrixCalc+k)+j)=*(*(array+k)+n-1) / *(*(array+k)+j); } else if(n-1-matrixPrimary[i][0]==m) { q=1; } else if(n-1-matrixPrimary[i][0]>m) { o=matrixPrimary[i][0];//當前行的首元位置 p=0;//次數 for(k=n-2-q;k>=o;k--)//從后向前查找自由元位置 { if(k==j) continue; freeElement[p++]=k; if(p==m)//說明已經找到 m個自由元 return freeElement; } } } return freeElement; }
求解示例圖:
1> p148-例4
2> 2.7(1)-1
3> 2.7(2)-1.1
4> 2.7(2)-1.2
5> 2.7(2)-1.3
6> 2.7(3)-1.1
7> 2.7(3)-1.2
8> 2.7(3)-1.3
9> 2.7(3)-1.4
10> p155-例6
以下是C語言求解的全部源代碼

#include <stdio.h> #include <stdlib.h> double undefined=-999;//標志位 void main() { int i,j,s,n; int res; double **array,*temp,**result; double *special;//特解 //temp double t1[6]={1,1,1,1,1,0}; double t2[6]={3,2,1,0,-3,0}; double t3[6]={0,1,2,3,6,0}; double t4[6]={5,4,3,2,6,0}; int homogeneous=1;//標識方程是否是齊次方程 void primaryRowChange(int s, int n, double **array); void printfDouble1Dimension(int n, double *array); void printfDouble2Dimension(int s, int n, double **array); int homogeneousResolve(int s, int n, int homogeneous, double **array, double **result); int nonHomegeneousResolve(int s, int n, double **array, double **result,double *special); //void printfInt2Dimension(int s, int n, int ** array); //int* getPrimary(int n,double *temp); //輸入說明 printf("輸入說明:行數代表S個線性方程,N代表未知數及常數項.\n"); printf("例如方程如下:\n"); printf("1x-2y+3z=4\n"); printf("-2x-4y+5z=10\n"); printf("如下輸入2行,4列:\n"); printf("1 -2 3 4\n"); printf("-2 -4 5 10\n\n"); //開始 printf("輸入行數:"); scanf("%d",&s); printf("輸入列數:"); scanf("%d",&n); //s=4; //n=6; //動態分配內存空間 array =(double**)malloc(s*sizeof(double*)); result =(double**)malloc(s*sizeof(double*)); special =(double*)malloc(n*sizeof(double)); for(i=0;i<s;i++) { temp=(double*)malloc(n*sizeof(double)); printf("請輸入第%d行數組:",i+1); for(j=0;j<n;j++) scanf("%lf",temp+j); /* switch(i) { case 0: temp=t1;//{1,1,1,1,1,0}; break; case 1: temp=t2;//{3,2,1,0,-3,0}; break; case 2: temp=t3;//{0,1,2,3,6,0}; break; case 3: temp=t4;//{5,4,3,2,6,0}; break; }*/ array[i]=temp; } //打印數組 printf("初等行列變換之前:\n"); printfDouble2Dimension(s,n,array); //判斷方程是否是齊次方程 for(i=0;i<s;i++) { if(*(*(array+i)+n-1)!=0)//如果最后一列,有不為0的 說明方程為非齊次方程 { homogeneous=0; break; } } primaryRowChange(s,n,array); printf("初等行列變換之后:\n"); printfDouble2Dimension(s,n,array); if(homogeneous)//齊次 { res = homogeneousResolve(s, n, homogeneous, array, result); switch (res) { case -1: printf("方程無解.\n"); break; case 0: printf("方程只有零解.\n"); break; default: printf("方程的基礎解系如下:\n"); printfDouble2Dimension(res,n-1,result); break; } } else//非齊次 { res=nonHomegeneousResolve(s,n,array,result,special); if(res==-1) printf("方程無解.\n"); else { printf("方程的基礎解系如下:\n"); printfDouble2Dimension(res,n-1,result); printf("方程的特解如下:\n"); printfDouble1Dimension(n-1,special); } } system("pause"); } //初等行變換 void primaryRowChange(int s, int n, double **array) { int i,j,k,ii,kk,flag; double temp; for(i=0,j=0;i<s-1;i++,j++)//s行,最外圍只需要變換s-1 { ii=i; //如果行的首元為0,向下查找一個不為0的,然后換行 if(*(*(array+i)+j) == 0) { flag=0; for(k=i+1;k<s;k++) { if(*(*(array+k)+j)!=0)//第k行與第i行交換 { for(kk=j;kk<n;kk++) { temp=*(*(array+k)+kk); *(*(array+k)+kk) = *(*(array+i)+kk); *(*(array+i)+kk) = temp; } flag =1; break; } } //判斷是交換成功,如果沒有成功,則i-- if(!flag) { i--; continue; } i--; j--; continue; } for(;ii<s-1;ii++) { if(*(*(array+ii+1)+j)==0) continue; temp =-*(*(array+ii+1)+j) / *(*(array+i)+j); for(k=j;k<n;k++) *(*(array+ii+1)+k) += *(*(array+i)+k) * temp; } } } //非齊次方程解的情況 int nonHomegeneousResolve(int s, int n, double **array, double **result, double *special) { int i,j,k,l; int r1,r2;//系數矩陣/增廣矩陣的秩 double **temp ;//用來存儲特解 int getRank(int s, int n, double **array); int homogeneousResolve(int s, int n, int homogeneous, double **array, double **result); r1=getRank(s,n-1,array); r2=getRank(s,n,array); if(r1!=r2) return -1;//無解 //特解 temp =(double**)malloc(r1*sizeof(double*)); homogeneousResolve(r1,n,0,array,temp); for(i=0;i<n;i++) *(special+i)=*(*(temp)+i); return homogeneousResolve(r1,n,1,array,result); } //齊次方程解的情況 int homogeneousResolve(int s, int n, int homogeneous, double **array, double **result) { int i,j,k,l,o,p,flag; int r;//秩rank int m;//自由元個數 int f;//最后一個非零行首元的位置 double sum1=0,sum2=0; double *temp = (double*)malloc(n*sizeof(double));//臨時行指針 int **matrixPrimary;//存儲矩陣首元位置及非零元個數 double **matrixCalc;//計算基礎解系 int *freeElement;//自由元位置 double **matrixTemp; //聲明函數 void printfDouble2Dimension(int s, int n, double **array); void printfInt2Dimension(int s, int n, int **array); int** getPrimary(int s, int n, double **array); int getRank(int s, int n, double **array); double** initMatrixCalc(int s, int n); int* getFreeElement(int r, int n,double **array, int **matrixPrimary, double **matrixCalc); void printfInt1Dimension(int n, int *array); void getPrimarySolution(int r, int n, int homogeneous, double **array, int **matrixPrimary, double **matrixCalc ,int *freeElement, double **result); //秩rank r = getRank(s,n,array); //判斷解的情況 m=n-1-r; if(m<0) return -1;//無解 else if(m==0) return 0;//只有零解 else { //初始化計算矩陣 matrixCalc = initMatrixCalc(r,n); //獲取矩陣首元信息 matrixPrimary = getPrimary(r,n,array); /*printf("打印計算矩陣:\n"); printfDouble2Dimension(r,n,matrixCalc); printf("打印矩陣首元信息:\n"); printfInt2Dimension(r,2,matrixPrimary); */ freeElement = getFreeElement(r, n, array, matrixPrimary,matrixCalc); //打印自由元位置 //printf("打印自由元位置:\n"); //printfInt1Dimension(m, freeElement); //計算基礎解系 getPrimarySolution(r, n, homogeneous, array, matrixPrimary, matrixCalc, freeElement ,result); //printfDouble2Dimension(m,n,result); return m; } } //init Matrix calc double** initMatrixCalc(int s, int n) { int i,j; double **array=(double**)malloc(s*sizeof(double*)); for(i=0;i<s;i++) { array[i] =(double*)malloc(n*sizeof(double)); *(*(array+i)+n-1)=1; for(j=0;j<n-1;j++) { *(*(array+i)+j)=undefined; } } return array; } //計算矩陣的秩 int getRank(int s, int n, double **array) { int flag; int i,j,r=s; //判斷非零行個數 for(i=0;i<s;i++) { flag=0; for(j=0;j<n;j++) { if(*(*(array+i)+j)!=0 && (*(*(array+i)+j)>0.01 || *(*(array+i)+j) <-0.01))//排除很小數, { flag=1; break; } } if(!flag)//當前行全為零,則r為i; { r=i; break; } } return r; } //查找某行非零個數及首元位置 int** getPrimary(int s, int n, double **array) { int i,j; int num=0,index=0; int **result=(int**)malloc(s*sizeof(int*)); int *temp; for(i=0;i<s;i++) { temp =(int*)malloc(2*sizeof(int)); num=0; index=0; for(j=0;j<n;j++) { if(*(*(array+i)+j)!=0) { if(num==0) index=j; num+=1; } } temp[0]=index; temp[1]=num; result[i]=temp; } return result; } //獲取自由元信息 int* getFreeElement(int r, int n, double **array, int **matrixPrimary, double **matrixCalc) { int i,j,k,o,p,q; int m=n-1-r;//n-1: int *freeElement =(int*)malloc(m*sizeof(int)); j=-1;//判斷是否有為0的變量 q=0;//如果當前行非零個數與自由元個數相等,則標記為1,自由元選擇起始位置左移一位 for(i=r-1;i>=0;i--)//查找自由元,及位置為0的 { if(*(*(matrixPrimary+i)+1)==1)//說明第i行只有一個變量,如果是齊次方程它的解一定為0 { j=*(*(matrixPrimary+i)+0); for(k=0;k<r;k++) *(*(matrixCalc+k)+j)=*(*(array+k)+n-1) / *(*(array+k)+j); } else if(n-1-matrixPrimary[i][0]==m) { q=1; } else if(n-1-matrixPrimary[i][0]>m) { o=matrixPrimary[i][0];//當前行的首元位置 p=0;//次數 for(k=n-2-q;k>=o;k--)//從后向前查找自由元位置 { if(k==j) continue; freeElement[p++]=k; if(p==m)//說明已經找到 m個自由元 return freeElement; } } } return freeElement; } //計算基礎解系 void getPrimarySolution(int r, int n, int homogeneous, double **array, int **matrixPrimary, double **matrixCalc ,int *freeElement, double **result) { int i,j,k,l,p; int m=n-1-r;//自由元 double sum1,sum2; double *temp,**matrixTemp; //計算基礎解系 for(i=0;i<m;i++) { matrixTemp=(double**)malloc(r*sizeof(double*)); //復制數組 for(j=0;j<r;j++) { temp =(double*)malloc(n*sizeof(double)); for(k=0;k<n;k++) *(temp+k)=*(*(matrixCalc+j)+k); matrixTemp[j]=temp; } //設置自由元為0或1 for(j=0;j<r;j++) { *(*(matrixTemp+j)+freeElement[i])=1;//自由元為1 for(k=0;k<m;k++) { if(k!=i) *(*(matrixTemp+j)+freeElement[k])=0;//自由元為0 } } //printfDouble2Dimension(r,n,matrixTemp); //計算 for(j=r-1;j>=0;j--) { p=*(*(matrixPrimary+j));//當前行起始位置 for(k=p;k<n;k++) { if(*(*(matrixTemp+j)+k)==undefined)//如果等於標志位,它可能是未知變量 { sum1=sum2=0; for(l=p;l<n;l++) { if(l==n-1) { sum1=*(*(array+j)+l) * *(*(matrixTemp+j)+l); } else if(l!=k) { sum2+=*(*(array+j)+l) * *(*(matrixTemp+j)+l); } } for(l=0;l<r;l++) *(*(matrixTemp+l)+k)=((homogeneous?0:sum1)-sum2)/ *(*(array+j)+k);//如果齊次sum1=0; //break; } } } result[i]=matrixTemp[0]; //printfDouble2Dimension(r,n,matrixTemp); } } //打印數組 void printfDouble2Dimension(int s, int n, double **array) { //printf("%d,%d",s,n); int i,j; for(i=0;i<s;i++) { for(j=0;j<n;j++) { printf("%6.2lf",*(*(array+i)+j)); } printf("\n"); } } void printfDouble1Dimension(int n, double *array) { int i; for(i=0;i<n;i++) { printf("%6.2lf",*(array+i)); } printf("\n"); } //打印二維數組 void printfInt2Dimension(int s, int n, int **array) { int i,j; for(i=0;i<s;i++) { for(j=0;j<n;j++) { printf("%4d",*(*(array+i)+j)); } printf("\n"); } } //打印一維數組 void printfInt1Dimension(int n, int *array) { int i; for(i=0;i<n;i++) { printf("%4d",*(array+i)); } printf("\n"); }