線性方程組 解的判別 與解的結構


一.線性方程組求解定理 

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 x+ a1x… + a1= 0 ,
a21 x+ a22 x… + a2= 0 ,

......................................................
asx+ asx… + asn = 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");
}
View Code

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM