10
1 3 4 0 2 0 4 -5 9 3
6 7 8 5 2 7 8 4 6 2
8 7 6 9 8 7 6 8 45 2
4 3 2 5 4 3 2 8 6 4
1 2 0 4 1 2 3 9 87 6
5 6 7 8 5 6 8 6 8 1
9 8 7 6 9 8 7 -9 2 3
5 6 3 5 4 1 8 7 9 2
-9 8 6 2 4 56 6 3 8 9
5 3 6 8 6 6 1 8 2 3
答案:7583304
d e t ( A n ∗ n ) = ∑ j = 1 n a i j A i j , ( i = 1 , 2 , . . . , n ) det(A_{n*n}) = \sum\limits_{j=1}^na_{ij}A_{ij},(i=1,2,...,n) det(An∗n)=j=1∑naijAij,(i=1,2,...,n)
或
d e t ( A n ∗ n ) = ∑ i = 1 n a i j A i j , ( j = 1 , 2 , . . . , n ) det(A_{n*n}) = \sum\limits_{i=1}^na_{ij}A_{ij},(j=1,2,...,n) det(An∗n)=i=1∑naijAij,(j=1,2,...,n)
#include
#include
using namespace std;
//构造第一行第line个元素的余子式
void StructMinor(double* matrix, int dimension, int line, double* minor){
int ptr=0;
for(int cnt1=1; cnt1<dimension; cnt1++) for(int cnt2=0; cnt2<dimension; cnt2++)
if(line!=cnt2) minor[ptr++] = matrix[cnt1*dimension+cnt2];
return;
}
double Determinant(double* matrix, int dimension){
//递归基,当矩阵中只有一个元素的时候,行列式的值即为实数值
if(dimension <= 1) return *matrix;
double minor[(dimension-1)*(dimension-1)];
double determinant = 0;
int sign = 1;
for(int cnt=0; cnt<dimension; cnt++){
//构造matrix[0][cnt]的余子式
StructMinor(matrix, dimension, cnt, minor);
//determinant=ΣELEMENT0j*A0j
determinant += sign*matrix[cnt]*Determinant(minor, dimension-1);
sign *= -1;
}
return determinant;
}
int main(){
int dimension;
int scale;
double matrix[100];
ifstream input("matrix.txt");
input >> dimension;
scale = dimension*dimension;
for(int cnt=0; cnt<scale; cnt++) input >> matrix[cnt];
cout << Determinant(matrix, dimension);
return 0;
}
d e t ( A n ∗ n ) = ∏ i = 1 n p i v o t e l e m e n t i det(A_{n*n}) = \prod\limits_{i=1}^npivot\ element_i det(An∗n)=i=1∏npivot elementi
#include
#include
using namespace std;
//通过高斯消元法化矩阵为upper triangle matrix
void GaussElimination2UTM(double* matrix, int dimension){
//注意cnt3一定要从矩阵最右侧运算至左侧,否则主元列对应元素归零,运算就无法正常进行
for(int cnt1=0; cnt1<dimension; cnt1++) for(int cnt2=cnt1+1; cnt2<dimension; cnt2++) for(int cnt3=dimension-1; cnt3>=cnt1; cnt3--)
matrix[cnt2*dimension+cnt3] += -1*matrix[cnt1*dimension+cnt3]*matrix[cnt2*dimension+cnt1]/matrix[cnt1*dimension+cnt1];
return;
}
double Determinant(double* matrix, int dimension){
double determinant=1;
GaussElimination2UTM(matrix, dimension);
//上三角阵对角线乘积即为行列式
for(int cnt=0; cnt<dimension; cnt++) determinant *= matrix[cnt*dimension+cnt];
return determinant;
}
int main(){
int dimension;
int scale;
double matrix[100];
ifstream input("matrix.txt");
input >> dimension;
scale = dimension*dimension;
for(int cnt=0; cnt<scale; cnt++) input >> matrix[cnt];
cout << Determinant(matrix, dimension) << '\n';
return 0;
}
计算结果出现明显错误,猜测原因是这个矩阵在进行行变换的时候出现了第四行第四列,极小的主元,所以原因在于double的精度对于这种算法依然不够
对于测试样例
10
1 3 67 0 2 0 4 -5 9 3
6 7 2 5 2 7 8 4 6 2
8 7 54 9 8 7 6 8 45 2
4 3 89 5 4 3 2 8 6 4
1 2 43 4 1 2 3 9 87 6
5 6 6 8 5 6 8 6 8 1
9 8 1 6 9 8 7 -9 2 3
5 6 2 5 4 1 8 7 9 2
-9 8 76 2 4 56 6 3 8 9
5 3 6 8 6 6 1 8 2 3
可以得出正确结果
上述数据改变了某一列,使得矩阵没有出现极小主元
可知该算法面对出现了极小主元的矩阵表现不佳,但是其时间复杂度是 O ( n 3 ) O(n^3) O(n3),相对于使用递归的算法很有效率
#include
#include
#include
using namespace std;
double GaussElimination2UTM(double* matrix, int dimension){
double sign=1;
double temp;
for(int cnt1=0; cnt1<dimension; cnt1++){
//在此引入置换操作,如果主元很小(小于0.001)那么进行行交换,此操作在行列式中引入了负号,消元函数返回行列式由于置换操作需要加入的符号
for(int cnt2=cnt1+1; cnt2<dimension; cnt2++){
if(abs(matrix[cnt1*dimension+cnt1])>1e-3) break;
for(int cnt3=0; cnt3<dimension; cnt3++){
temp=matrix[cnt1*dimension+cnt3]; matrix[cnt1*dimension+cnt3]=matrix[cnt2*dimension+cnt3]; matrix[cnt2*dimension+cnt3]=temp;}
sign*=-1;
}
for(int cnt2=cnt1+1; cnt2<dimension; cnt2++) for(int cnt3=dimension-1; cnt3>=cnt1; cnt3--)
matrix[cnt2*dimension+cnt3] += -1*matrix[cnt1*dimension+cnt3]*matrix[cnt2*dimension+cnt1]/matrix[cnt1*dimension+cnt1];
}
return sign;
}
double Determinant(double* matrix, int dimension){
double determinant=1;
determinant=GaussElimination2UTM(matrix, dimension);
for(int cnt=0; cnt<dimension; cnt++) determinant *= matrix[cnt*dimension+cnt];
return determinant;
}
int main(){
int dimension;
int scale;
double matrix[100];
ifstream input("matrix.txt");
input >> dimension;
scale = dimension*dimension;
for(int cnt=0; cnt<scale; cnt++) input >> matrix[cnt];
cout << Determinant(matrix, dimension) << '\n';
return 0;
}
为了解决精度问题,考虑到测试样例只输入有理数,所以尝试了使用分数表示每个数字,但是由于long long类型长度有限,表达极小大数依然有困难,所以依然算不了上面的10阶的测试样例,不过也算个有趣的尝试。同时这种计算方法可以避免在结果在计算过程中丢失精度
#include
#include
#include
class rationalnumber{
public:
long long numerator;
long long denominator;
};
using namespace std;
rationalnumber ReductionOfFraction(rationalnumber A){
bool sign;
long long gcd, mod, temp;
rationalnumber result;
if(A.numerator == 0){
result.numerator = 0;
result.denominator = 1;
}
else{
if(sign = (A.numerator < 0)) A.numerator = -A.numerator;
if(A.numerator%A.denominator == 0){
result.numerator = A.numerator/A.denominator; result.denominator = 1;}
else{
temp = A.numerator>A.denominator?A.numerator:A.denominator;
gcd = A.numerator<A.denominator?A.numerator:A.denominator;
mod = temp%gcd;
while(mod!=0){
temp = gcd;
gcd = mod;
mod = temp%gcd;
}
result.numerator = A.numerator/gcd;
result.denominator = A.denominator/gcd;
}
if(sign) result.numerator = -result.numerator;
}
return result;
}
rationalnumber NegativeOfFraction(rationalnumber A){
rationalnumber result;
result.numerator = -A.numerator;
result.denominator = A.denominator;
return result;
}
rationalnumber AdditionOfFraction(rationalnumber A, rationalnumber B){
rationalnumber result;
result.numerator = A.numerator*B.denominator + B.numerator*A.denominator;
result.denominator = A.denominator * B.denominator;
result=ReductionOfFraction(result);
return result;
}
rationalnumber MultiplicationOfFraction(rationalnumber A, rationalnumber B){
rationalnumber result;
result.numerator = A.numerator * B.numerator;
result.denominator = A.denominator * B.denominator;
result=ReductionOfFraction(result);
return result;
}
rationalnumber DivisionOfFraction(rationalnumber A, rationalnumber B){
rationalnumber result;
result.numerator = A.numerator * B.denominator;
result.denominator = A.denominator * B.numerator;
result=ReductionOfFraction(result);
return result;
}
//通过高斯消元法化矩阵为upper triangle matrix
void GaussElimination2UTM(rationalnumber* matrix, int dimension){
//注意cnt3一定要从矩阵最右侧运算至左侧,否则主元列对应元素归零,运算就无法正常进行
for(int cnt1=0; cnt1<dimension; cnt1++) for(int cnt2=cnt1+1; cnt2<dimension; cnt2++) for(int cnt3=dimension-1; cnt3>=cnt1; cnt3--)
matrix[cnt2*dimension+cnt3] =
AdditionOfFraction(
matrix[cnt2*dimension+cnt3],
NegativeOfFraction(
DivisionOfFraction(
MultiplicationOfFraction(matrix[cnt1*dimension+cnt3], matrix[cnt2*dimension+cnt1]),
matrix[cnt1*dimension+cnt1]
)
)
);
return;
}
rationalnumber Determinant(rationalnumber* matrix, int dimension){
rationalnumber determinant;
determinant.denominator = 1;
determinant.numerator = 1;
GaussElimination2UTM(matrix, dimension);
//上三角阵对角线乘积即为行列式
for(int cnt=0; cnt<dimension; cnt++) determinant = MultiplicationOfFraction(determinant, matrix[cnt*dimension+cnt]);
return determinant;
}
int main(){
int dimension;
int scale;
double fraction;
rationalnumber determinant;
rationalnumber matrix[100];
ifstream input("matrix.txt");
input >> dimension;
scale = dimension*dimension;
for(int cnt=0; cnt<scale; cnt++){
input >> fraction;
for(matrix[cnt].denominator = 1; abs(fraction-(int)fraction)>10e-17; matrix[cnt].denominator*=10, fraction*=10);
matrix[cnt].numerator=(int)fraction;
}
determinant = Determinant(matrix, dimension);
cout << (double)determinant.numerator/(double)determinant.denominator << '\n';
return 0;
}
使用行列式的定义式进行计算
d e t ( A n ∗ n ) = ∑ a l l o f p e r m u t a t i o n s ( − 1 ) τ ( p 1 p 2 . . . p n ) a 1 p 1 a 2 p 2 . . . a n p n det(A_{n*n})=\sum\limits_{all\ of\ permutations}(-1)^{\tau(p_1p_2...p_n)}a_{1p_1}a_{2p_2}...a_{np_n} det(An∗n)=all of permutations∑(−1)τ(p1p2...pn)a1p1a2p2...anpn
τ ( p 1 p 2 . . . p n ) i s t h e i n v e r s i o n n u m b e r o f p e r m u t a t i o n p 1 p 2 . . . p n . {\tau(p_1p_2...p_n)}\ is\ the\ inversion\ number\ of\ permutation\ p_1p_2...p_n. τ(p1p2...pn) is the inversion number of permutation p1p2...pn.
#include
#include
using namespace std;
int dimension;
char permutation[10];
double matrix[100];
double Determinant(int depth, double sign){
double result;
//递归基,在递归树的叶子返回定义的求和式的其中一项
if(depth>=dimension){
result = sign;
for(int cnt=0; cnt<dimension; cnt++) result *= matrix[cnt*dimension+permutation[cnt]];
}
else{
int temp;
//不交换的情况,对逆序数无贡献
result = Determinant(depth+1, sign);
//将后续几个元素分别于第一个元素进行交换,逆序数加一
for(int cnt=depth+1; cnt<dimension; cnt++){
//交换
temp = permutation[depth];
permutation[depth] = permutation[cnt];
permutation[cnt] = temp;
//计算此情况下所有值之和
result += Determinant(depth+1, -1*sign);
//换回
temp = permutation[depth];
permutation[depth] = permutation[cnt];
permutation[cnt] = temp;
}
}
return result;
}
int main(){
int scale;
ifstream input("matrix.txt");
input >> dimension;
for(int cnt=0; cnt<dimension; cnt++) permutation[cnt] = cnt;
scale = dimension*dimension;
for(int cnt=0; cnt<scale; cnt++) input >> matrix[cnt];
cout << Determinant(0,1) << '\n';
return 0;
}