克拉默法则
解线性方程组最基础的方法就是使用克拉默法则,需要注意的是,该方程组必须是线性方程组。
假设有方程组如下:
{ a 11 x 1 + a 12 x 2 + ⋯ + a 1 n x n = b 1 a 21 x 1 + a 22 x 2 + ⋯ + a 2 n x n = b 2 ⋯ ⋯ ⋯ a n 1 x 1 + a n 2 x 2 + ⋯ + a n n x n = b n \begin{cases} a_{11}x_1+a_{12}x_2+\cdots+a_{1n}x_n=b_1\\ a_{21}x_1+a_{22}x_2+\cdots+a_{2n}x_n=b_2\\ \cdots \qquad \qquad\cdots \qquad \qquad \cdots \\ a_{n1}x_1+a_{n2}x_2+\cdots+a_{nn}x_n=b_n\\ \end{cases} ⎩ ⎨ ⎧a11x1+a12x2+⋯+a1nxn=b1a21x1+a22x2+⋯+a2nxn=b2⋯⋯⋯an1x1+an2x2+⋯+annxn=bn
将其转换为矩阵形式
A x ⃗ = b ⃗ A\vec{x}=\vec{b} Ax=b
[ a 11 a 12 ⋯ a 1 n a 21 a 22 ⋯ a 2 n ⋮ ⋮ ⋱ ⋮ a m 1 a m 2 ⋯ a m n ] [ x 1 x 2 ⋮ x n ] = [ b 1 b 2 ⋮ b n ] \begin{bmatrix} {a_{11}}&{a_{12}}&{\cdots}&{a_{1n}}\\ {a_{21}}&{a_{22}}&{\cdots}&{a_{2n}}\\ {\vdots}&{\vdots}&{\ddots}&{\vdots}\\ {a_{m1}}&{a_{m2}}&{\cdots}&{a_{mn}}\\ \end{bmatrix} \begin{bmatrix} {x_{1}}\\ {x_{2}}\\ {\vdots}\\ {x_{n}}\\ \end{bmatrix}= \begin{bmatrix} {b_{1}}\\ {b_{2}}\\ {\vdots}\\ {b_n} \end{bmatrix} a11a21⋮am1a12a22⋮am2⋯⋯⋱⋯a1na2n⋮amn x1x2⋮xn = b1b2⋮bn
根据克拉默法则有:
x i = ∣ A i ∣ ∣ A ∣ x_i=\frac{|A_i|}{|A|} xi=∣A∣∣Ai∣
A i = [ a 11 ⋯ a 1 i − 1 b 1 a 1 i + 1 ⋯ a 1 n a 21 ⋯ a 2 i − 1 b 2 a 2 i + 1 ⋯ a 2 n ⋮ ⋮ ⋱ ⋮ a n 1 ⋯ a n i − 1 b n a n i + 1 ⋯ a n n ] A_i= \begin{bmatrix} {a_{11}}&{\cdots}&{a_{1i-1}}&{b1}&{a_{1i+1}}&{\cdots}&{a_{1n}}\\ {a_{21}}&{\cdots}&{a_{2i-1}}&{b2}&{a_{2i+1}}&{\cdots}&{a_{2n}}\\ {\vdots}&{\vdots}&{\ddots}&{\vdots}\\ {a_{n1}}&{\cdots}&{a_{ni-1}}&{bn}&{a_{ni+1}}&{\cdots}&{a_{nn}}\\ \end{bmatrix} Ai= a11a21⋮an1⋯⋯⋮⋯a1i−1a2i−1⋱ani−1b1b2⋮bna1i+1a2i+1ani+1⋯⋯⋯a1na2nann
代码
实现方法可以参考行列式求值(C++)、插值(一)——多项式插值(C++)
//克拉默法则求解线性方程组
/*
5x1+2x2-2x3=1
x1+4x2+x3=2
x1-2x2+4x3=-1
*/
#include<iostream>
#include<cmath>
//使用代数余子式进行求解
double determinant_value(double **D,int n)
{if(n==1){return D[0][0];}else if(n==0){throw "error: determinant is empty";}char flag = 1;//符号位double D_value = 0.0;double **D_temp = new double*[n];for (int i = 0; i < n;i++){D_temp [i]= new double[n];for(int j=0;j<n;j++){D_temp[i][j]=D[i][j];}}// 转为上三角for (int i = 0; i < n; i++){if (D_temp[i][i] == 0){int j = i + 1;// 将主对角线上的值转为非0值for (; j < n; j++){if (D_temp[j][i] != 0){double temp;for (int k = 0; k < n; k++){temp = D_temp[i][k];D_temp[i][k] = D_temp[j][k];D_temp[j][k] = temp; // 交换两行}flag = -flag;break;}}if (j == n){return D_value;}}// 将主对角线下面的值转为0for (int j = i + 1; j < n; j++){double temp = D_temp[j][i] / D_temp[i][i];for (int k = i; k < n; k++){D_temp[j][k] -= temp * D_temp[i][k];}}}// 计算行列式的值D_value = 1.0;for (int i = 0; i < n; i++){D_value *= D_temp[i][i];}D_value*=flag;for (int i = 0; i < n;i++){delete[] D_temp[i];}delete [] D_temp;return D_value;
}
//克拉默法则求解线性方程组
void Kramer(double **A,double *b,double *x,int n)
{double **A_i=new double*[n];double A_value=determinant_value(A,n);if(A_value==0){std::cout<<"该方程组不是线性方程组"<<std::endl;exit(0);}for (int i = 0; i < n; i++){A_i[i] = new double[n];for (int j = 1; j < n; j++){A_i[i][j] = A[i][j];}}//下面是为了求D_i,每次只需要修改两列数据for (int i = 0; i < n;i++){if(i==0){for(int j = 0;j < n;j++){A_i[j][0]=b[j];}}else{for(int i2 = 0;i2 < n;i2++){A_i[i2][i-1]=A[i2][i-1];A_i[i2][i]=b[i2];}}// for(int i2 = 0;i2 < n;i2++)// {// for (int j2 = 0;j2 < n;j2++)// {// std::cout<<A_i[i2][j2]<<" ";// }// std::cout<<std::endl;// }//求多项式系数x[i] = determinant_value(A_i, n) / A_value;}for (int i = 0; i < n; i++){delete[] A_i[i];}delete[] A_i;
}
int main()
{int n;//矩阵维度std::cout<<"请输入矩阵维度:";std::cin>>n;double *x=new double[n];double **A = new double *[n];std::cout<<"请输入矩阵A的元素:"<<std::endl;for(int i = 0;i < n;i++){A[i] = new double [n];for(int j = 0;j < n;j++){std::cin>>A[i][j];}}double *b = new double [n];std::cout<<"请输入矩阵b的元素:"<<std::endl;for(int i = 0;i < n;i++){std::cin>>b[i];}Kramer(A, b, x, n);for (int i = 0; i < n; i++){std::cout<<"x"<<i+1<<"="<<x[i]<<" ";}for (int i = 0; i < n; i++){delete[] A[i];}delete[] A;delete [] b;delete[] x;return 0;
}
结果分析
运行结果如下:
matlab结果如下:
此方法虽然可以求解,但是存在一个问题,就是当矩阵维度较大时,程序运行时间会很长,所以在一些精度要求不高的地方,不需要使用此方法。