克拉默法则
解线性方程组最基础的方法就是使用克拉默法则,需要注意的是,该方程组必须是线性方程组。
假设有方程组如下:
{
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;
}
}
// 将主对角线下面的值转为0
for (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结果如下:
此方法虽然可以求解,但是存在一个问题,就是当矩阵维度较大时,程序运行时间会很长,所以在一些精度要求不高的地方,不需要使用此方法。