• LUP分解法求解线性方程组


    本节我们讨论如何用LUP分解法求解线性方程组,对于含有n个未知变量x1,x2,x3,…,xn的线性方程组:

    image

    同时满足方程组中所有方程的一个数值集:x1,x2,…,xn称为方程组的解。

    将方程组改写成矩阵向量等式:

    image

    记为:

    Ax=b

    如果A为非奇异矩阵,那么A存在逆矩阵,亦即方程组有解。

    LUP分解的思想是找出三个n*n的矩阵,L、U和P,满足

    PA=LU

    其中,L是一个单位下三角矩阵,U是一个上三角矩阵,P是一个置换矩阵。则称满足上述等式的L、U和P为矩阵A的LUP分解

    等式Ax=b两边同乘以P,变形为PAx=Pb,亦即:

    LUx=Pb

    设y=Ux,其中x就是我们要求的向量解。我们首先通过正向替换求解下三角系统:

    Ly=Pb

    得到未知变量y。然后,通过正向替换求解上三角系统:

    Ux=y

    得到未知变量x。

    由于置换矩阵P是可逆的,等式PA=LU两边同乘以P-1,得:

    A=P-1LU

    =P-1Ly

    =P-1Pb

    =b

    于是x就是Ax=b的解。

    调用方法:

        linear::CLinearEqualtion l(3);
        l.init_A("A.txt");
        l.init_b("b.txt");
        l.lu_decomposition();
        l.lup_solve();
        l.show_y();
        l.show_x();
        l.save_solution();

    C++实现:

    #include <iostream>
    #include <vector>
    #include <cassert>
    #include <fstream>
    
    using namespace std;
    
    namespace linear
    {
    #define array_1(__type) std::vector<__type>
    #define array_2(__type) std::vector<array_1(__type)>
    
        class CLinearEqualtion
        {
            /*
            使用方法:
            1. 定义计算方程组的类对象,并初始化其系数矩阵的大小
            linear::CLinearEqualtion l(3);
    
            2. 读取系数阵 A
            l.init_A("A.txt");
    
            3. 读取 b
            l.init_b("b.txt");
    
            4. 对系数矩阵进行lu分解
            l.lu_decomposition();
    
            5. 求解方程组
            l.lup_solve();
    
            6. 显示反向替换的解
            l.show_y();
    
            7. 显示正向替换的解
            l.show_x();
    
            8. 保存方程的解
            l.save_solution();
    
            A.txt
            1    5    4
            2    0    3
            5    8    2
    
            b.txt
            12
            9
            5
    
            x[0] = -0.157895
            x[1] = -0.0526316
            x[2] = 3.10526
            */
        private:
            array_2(double) A;
            array_2(double) L;
            array_2(double) U;
    
            array_1(double) b;
            array_1(int) p;
    
            array_1(double) x;
            array_1(double) y;
    
        public:
            CLinearEqualtion(int n)
            {
                assert(n>1);
    
                A = array_2(double)(n);
                L = array_2(double)(n);
                U = array_2(double)(n);
                for (int i= 0; i < n;i++)
                {
                    A[i] = array_1(double)(n);
                    L[i] = array_1(double)(n);
                    U[i] = array_1(double)(n);
                }
                b = array_1(double)(n);
                x = array_1(double)(n);
                y = array_1(double)(n);
                p = array_1(int)(n);
            } // !CLinearEqualtion(int n)
            virtual ~CLinearEqualtion(){} // !virtual ~CLinearEqualtion()
    
        public:
            void init_A(array_2(double) _A)
            {
                for (int i = 0; i < _A.size(); i++)
                    A[i].assign(_A[i].begin(), _A[i].end());
            } // !void init_A(array_2(double) _A)
    
            void init_A(std::string _fileName)
            {
                std::ifstream in(_fileName.c_str());
                int i = 0;
                int j = 0;
                while(!in.eof())
                {
                    double e = 0;
                    in>>e;
                    std::cout<<e<<std::endl;
                    A[i][j] = e;
                    if (j==A.size() - 1)
                    {
                        i++;
                        j = 0;
                    }
                    else
                    {
                        j++;
                    }
                }
            } // !void init_A(std::string _fileName)
    
            void init_b(std::string _fileName)
            {
                std::ifstream in(_fileName.c_str());
                int i = 0;
                while(!in.eof())
                {
                    double e = 0;
                    in>>e;
                    std::cout<<e<<std::endl;
                    b[i++] = e;
                }
            } // !void init_b(std::string _fileName)
    
            void lu_decomposition()
            {
                int n = A.size(); // get array size
                for (int i = 0; i < n; i++)
                    p[i] = i;
                for (int k = 0; k < n; k++)
                {
                    int max = 0;
                    int k_ = k;
                    // get max e in col k.
                    for (int i = k; i < n; i++)
                    {
                        if (fabs(A[i][k]) > max)
                        {
                            max = fabs(A[i][k]);
                            k_ = i;
                        }
                    }
                    // make sure not all is zero.
                    if (max == 0)
                        assert("singular matrix");
    
                    // swap cur row,max row.
                    if (k != k_)
                    {
                        swap(p[k], p[k_]);
                        for (int i = 0; i < n; i++)
                            swap(A[k][i], A[k_][i]);                    
                    }
                    
                    for (int i = k + 1; i < n; i++)
                    {
                        // gen v
                        A[i][k] /= A[k][k];
                        for (int j = k + 1; j < n; j++)
                        {
                            A[i][j] -= A[i][k] * A[k][j];
                        }
                    }
                }
    
                init_LU();
            } // !void lu_decomposition()
    
            void init_LU()
            {
                int n = A.size(); // get array size
    
                for (int i = 0; i < n; i++)
                {
                    for (int j = 0; j < n; j++)
                    {
                        if (i > j)
                        {
                            L[i][j] = A[i][j];
                        } 
                        else
                        {
                            U[i][j] = A[i][j];
                            if (i == j)
                                L[i][i] = 1;
                        }
                    }
                }
    
            } // !void init_LU()
    
            void lup_solve()
            {
                int n = A.size();
                int i = 0, j = 0;
                for (i = 0; i < n; i++)
                {
                    x[i] = 0;
                    y[i] = 0;
                }
    
                for (i = 0; i < n; i++)
                {
                    y[i] = b[p[i]];
                    for (j = 0; j < i; j++)
                        y[i] -= L[i][j] * y[j];
                }
                for (i = n - 1; i >= 0; i--)
                {
                    double delt = y[i];
                    for (j = n - 1; j > i; j--)
                        delt -= U[i][j] * x[j];
                    x[i] = delt / U[i][j];
                }
            } // !void lup_solve()
    
            void show_y()
            {
                int n = A.size();
                std::cout << "###" << std::endl;
                for (int i = 0; i < n; i++)
                {
                    std::cout << "y[" << i << "]=" << y[i] << std::endl;
                }
            } // !void show_y()
    
            void show_x()
            {
                int n = A.size();
                std::cout << "###" << std::endl;
                for (int i = 0; i < n; i++)
                    std::cout << "x[" << i << "]=" << x[i] << std::endl;
            } // !void show_x()
    
    
            void save_solution()
            {
                int n = A.size();
                ofstream out("result.txt", ios::out);
                out << "-------------------------------------" << std::endl;
                std::cout << "-------------------------------------" << std::endl;
                for (int i = 0; i < n; i++)
                {                
                    out << "x[" << i << "] = " << x[i]<< std::endl;
                    std::cout << "x[" << i << "] = " << x[i]<< std::endl;
                }
                out << "-------------------------------------" << std::endl;
                std::cout << "-------------------------------------" << std::endl;
                out.close();
            }
        };
    }

    链接:http://pan.baidu.com/s/1hqJes4k 密码:elwz

  • 相关阅读:
    [ZJOI2010]基站选址
    [SDOI2008]Sue的小球
    访问计划
    奥义商店
    codeforces 809E Surprise me!
    codeforces 888G Xor-MST
    [HAOI2015]数字串拆分
    小奇分糖果
    小奇的花园
    BZOJ4711 小奇挖矿
  • 原文地址:https://www.cnblogs.com/BigBigLiang/p/4962553.html
Copyright © 2020-2023  润新知