上个星期,我们的线性代数老师让我们编程计算行列式,这个星期又让我们算逆矩阵
虽然这个老师上课老爱吹水,但是至少让我们编的程序是可行的
根据某定理:n阶行列式等于它的任一行的元素与其对应的代数余子式的乘积之和;即:
D=ai1*Ai1+ai2*Ai2+.....+ain*Ain(i= 1,2,3...n)
取i==1时展开:
D=a11*A11+a12*A12+...a1n*A1n;
设递归函数rec(n,D)为D行列的值;n:行列的阶;
根据定理按照第一行展开可得:
rec(n,D)=sumj ( (-1)^1+j * a1j * rec(n-1,A1j) ); A1j为a1j的代数余子式;sumj为求和
n==1 时,rec(1,D)==D;
#include<iostream>
#include<vector>
using std::vector;
double rec(int n, vector<double>D) {
if (n == 1) {
return D.back();
}
int e = 1;//设置符号
double sum = 0;
for (int k = 0; k < n; k++) {
vector<double>d;
for (int i = 1; i < n; i++) {//i==1表示从第一行开始,因为第0行是被展开的量;
for (int j = 0; j < n; j++) {
if (k == j)continue; //划去同列元素;
d.push_back(D[i*n + j]);
}
}
sum += D[k] * e*rec(n - 1, d);
e *= -1;
}
return sum;
}
int main() {
int n;
std::cin >> n;
vector<double>d;
for (int i = 0; i < n; i++) {
for (int j = 0; j < n; j++) {
double a;
std::cin >> a;
d.push_back(a);
}
}
std::cout << rec(n, d);
return 0;
}
计算逆矩阵:
A^-1 = A*/ | A |; A*为伴随矩阵
概念不叙述了:
/*
各函数表示的含义:
project: 得到aij的余子式;
rec : 计算行列式D的值
AT : 将矩阵进行转置;
A_ : 计算A的逆矩阵;
*/
#include<iostream>
#include<vector>
#include<iomanip>
#include<cstring>
#include<cmath>
using std::vector;
const double eps = 1e-3;
vector<double>project(int n, vector<double>&D, int ii, int jj) {//分出余子式;
vector<double>c;
for (int i = 0; i < n; i++) {
for (int j = 0; j < n; j++) {
if (i == ii || j == jj)continue;
c.push_back(D[i*n + j]);
}
}
return c;
}
double rec(int n, vector<double>&D) {
if (n == 1) {
return D.back();
}
int e = 1;
double sum = 0;
for (int k = 0; k < n; k++) {
vector<double>d;
d = project(n, D, 0, k);
sum += D[k] * e*rec(n - 1, d);
e *= -1;
}
return sum;
}
vector<double>AT(int n, vector<double>&D) {//转置;
vector<double>c;
for (int i = 0; i < n; i++) {
for (int j = 0; j < n; j++) {
c.push_back(D[j*n + i]);
}
}
return c;
}
vector<double>A_(int n, vector<double>&D) {//计算逆矩阵;
vector<double>c;
//先将每个元素的代数余子式计算出来;
double A = rec(n, D);//计算D的行列值;
if (A == 0)return c;//如果A为0则无逆矩阵:返回一个空向量判断;
for (int i = 0; i < n; i++) {
for (int j = 0; j < n; j++) {
vector<double>Aij;
Aij = project(n, D, i, j);
double aij = rec(n - 1, Aij) / A;
if ((i + j) & 1)aij *= -1;
c.push_back(aij);
}
}
//转置:
c = AT(n, c);
return c;
}
int main() {
int n;
std::cin >> n;
vector<double>d;
for (int i = 0; i < n; i++) {
for (int j = 0; j < n; j++) {
double a;
std::cin >> a;
d.push_back(a);
}
}
vector<double>D = A_(n, d);
//输出;
//保留两位小数:
if (D.empty()) {
std::cout << "该矩阵为奇异阵";
return 0;
}
for (int i = 0; i < n; i++) {
for (int j = 0; j < n; j++) {
if (fabs(D[i*n + j]-int(D[i*n+j])) <= eps) {
std::cout << std::setw(6) << int(D[i*n+j]); continue;
}
std::cout << std::fixed << std::setprecision(2) << std::setw(6) << D[i*n + j];
}
std::cout << '\n' << '\n';
}
return 0;
}
分析一下时间复杂度:
行列式的计算rec:令rec(n)的复杂度为T(n)递归式执行了n次rec(n-1)
则有T(n)=nT(n-1)+o(1)
T(n) =n!
然后又是 A_函数n^2* T(n)=O(n^2*n!);
并且常数比较大,所以到n==10就不能秒算了
时间复杂分析更新与2022-5-8