【C#】 迴圈小練習_線性方程式求解

  • 232
  • 0
  • C#
  • 2021-05-14

線性方程式,高斯消去法

高斯消去法的基本原理
AX=B
其中,A為係數矩陣,X為變數列矩陣,B為常數列矩陣。
假設方程組有equnum方程式個數、有varnum未知個數
我們可以將係數矩陣A和常數列矩陣B,組合成一個廣域矩陣A',在對矩陣中的每一個元素進行消去去操作。
請參閱:演算法筆記- Linear Equation
求解:



    class Program
    {
        static readonly int MaxNum = 10;
        static int[,] ary = {{1,2,-5,5},
                          {2,4,6,1},
                          {3,1,7,4}};

        static int[] un_result = new int[MaxNum];

        static void Main(string[] args)
        {
            //高斯消去法
            //線性方程式

            int i, type;
            int equnum, varnum;
            int[] result = new int[MaxNum]; //儲存方程式的解
            equnum = 3; //方程式個數
            varnum = 3; //未知數個數

            type = GaussFun(equnum, varnum, result);
            if (type == -1)  //無解
            {
                Console.WriteLine("該方程式無解!\n");
            }
            else if (type == -2) //只有浮點數解
            {
                Console.WriteLine("該方程式只有浮點數解,無整數解!\n");
            }
            else if (type > 0) //無窮多解
            {
                Console.WriteLine(string.Format("該方程式有無窮多解!自由變數量為{0}\n", type));
                for (i = 0; i < varnum; i++)
                {
                    if (un_result[i] != 0) //判斷不確定變數
                    {
                        Console.WriteLine(string.Format("x{0}是不確定的\n", i + 1));
                    }
                    else //輸出一組解
                    {
                        Console.WriteLine(string.Format("x{0}:{1}\n", i + 1, result[i]));
                    }
                }
            }
            else //唯一解
            {
                Console.WriteLine("該方程式的解為:\n");
                for (i = 0; i < varnum; i++)
                {
                    Console.WriteLine(string.Format("x{0}:{1}\n", i + 1, result[i]));
                }
            }
            Console.ReadLine();
        }

        #region 高斯消去演算法
        static int GaussFun(int equ, int var, int[] result)
        {
            int i, j, k;
            int col = 0;
            int max;
            int temp, un_x_num, un_index = 0;
            int nu1, nu2;
            int gcdtmp, lcmtmp; //利用遞迴求GCD(最大公因數)與LCM(最小公倍數)
            int ta, tb;

            for (k = 0; k < equ && col < var; k++, col++)  //迴圈處理每一行 
            {
                max = k;        //儲存絕對值最大的行號
                for (i = k + 1; i < equ; i++)
                {
                    if (Math.Abs(ary[i, col]) > Math.Abs(ary[max, col]))
                    {
                        //儲存絕對值最大的行號
                        max = i;
                    }
                }
                if (max != k)
                {
                    for (j = k; j < var + 1; j++)  //當前列左側為0,交換當前右側資料
                    {
                        temp = ary[k, j];
                        ary[k, j] = ary[max, j];
                        ary[max, j] = temp;

                    }
                }
                if (ary[k, col] == 0)  //如果col列第k行以下是0,則處理目前行的下一列
                {
                    k--;
                    continue;
                }
                for (i = k + 1; i < equ; i++) //尋找消去的行
                {
                    if (ary[i, col] != 0)
                    {
                        nu1 = Math.Abs(ary[i, col]);
                        nu2 = Math.Abs(ary[k, col]);
                        while (nu2 != 0)   //輾轉相除求最大公因數 
                        {
                            temp = nu2;
                            nu2 = nu1 % nu2;
                            nu1 = temp;
                        }
                        gcdtmp = nu1;
                        lcmtmp = (Math.Abs(ary[i, col]) * Math.Abs(ary[k, col])) / gcdtmp;

                        ta = lcmtmp / Math.Abs(ary[i, col]);
                        tb = lcmtmp / Math.Abs(ary[k, col]);
                        if (ary[i, col] * ary[k, col] < 0) //如果符號不相符
                        {
                            tb = -tb; // 異號兩邊相加
                        }
                        for (j = col; j < var + 1; j++) //迴圈消去
                        {
                            ary[i, j] = ary[i, j] * ta - ary[k, j] * tb;
                        }
                    }
                }
            }
            for (i = k; i < equ; i++) //判斷最後一行,最後一列
            {
                if (ary[i, col] != 0) //若不等於0 表示無解
                {
                    return -1;
                }
            }
            if (k < var) //不確定的變數至少有 VAR-K 個
            {
                for (i = k - 1; i >= 0; i--) //權圈處理非零行
                {
                    un_x_num = 0; //判斷該行不確定變數的數量
                    for (j = 0; j < var; j++)
                    {
                        if (ary[i, j] != 0 && un_result[j] != 0) //不確定變數判斷
                        {
                            un_x_num++; //不確定變數+1
                            un_index = j;
                        }
                    }
                    if (un_x_num > 1)
                    {
                        continue; //若超過一個無法求解
                    }
                    temp = ary[i, var];
                    for (j = 0; j < var; j++)
                    {
                        if (ary[i, j] != 0 && j != un_index)
                        {
                            temp -= ary[i, j] * result[j];//每次剪去前一係數及解的積
                        }
                    }
                    result[un_index] = temp / ary[i, un_index]; //求出變數
                    un_result[un_index] = 0;  //該變數是確定的
                }
                return var - k;  //自由變數有Var -K
            }
            for (i = var - 1; i >= 0; i--) //求解  
            {
                temp = ary[i, var];
                for (j = i + 1; j < var; j++)
                {
                    if (ary[i, j] != 0)
                    {
                        temp -= ary[i, j] * result[j]; //每次減去前一項係數及解的積
                    }
                }

                if (temp % ary[i, j] != 0) //如不能整除
                {
                    return -2; //傳回有浮點數解、但無整數解
                }
                result[i] = temp / ary[i, i];
            }
            return 0; //唯一解
        }
        #endregion

    }

水滴可成涓流,涓流可成湖泊大海。
汲取累積知識,將知識堆積成常識;將常識探究成學識;將學識簡化為知識;授人自省。