背景:
这个学期开了线性代数的课,在矩阵的逆这一节中出现了伴随矩阵,就是求出每一个位置上的对称位置的代数余子式后得到一个新的矩阵。这个新的矩阵就是伴随矩阵。
有了一种新的矩阵自然而然地就有了一种新的题型。给定一个矩阵A,求它的伴随矩阵或者根据它的伴随矩阵来求出它的逆矩阵。而对于n阶矩阵,要求出它的伴随矩阵,就得求出它的n*n个代数余子式,对于超过3阶的矩阵来说,计算就过于繁琐了,并且叫你求4阶方阵的伴随矩阵是常有的事情。所以我就想能不能写一个程序,输入一个n阶方阵,就求出对应的伴随矩阵。
程序整体框架:
要完成这个程序,应该有方阵阶数的输入,方阵元素的输入,求方阵的伴随矩阵,输出方阵的伴随矩阵这四个步骤,所以主函数大致是这样的。
int main()
{
int A[10][10]; //二维数组存放方阵A
int Adj[10][10]; //用于存档A的伴随矩阵的二维数组
int n;
GetMat(&n,A); //用于输入方阵A的函数
Adjoint_matrix(A,n,Adj); //求伴随矩阵的函数
cout<<"方阵A的伴随矩阵为:\n";
Show_Mat(Adj,n); //最后将伴随矩阵打印出来
}
显而易见,程序的难点也是重点在于求伴随矩阵的函数上。
几个重要步骤:
一、将一个n阶方阵去掉第i行第j列后形成一个(n-1)阶的方阵。
在求方阵A中某个元素的代数余子式时,需要求出每个元素去掉所在行所在列后的行列式的值。
在求一个n阶方阵的行列式时,当n较大时,根据“行列式D(n)的第i行(列)元素与其对应的代数余子式的乘积之和等于行列式D(n)”,需要求n个代数余子式,此时又要得到去掉某一行某一列后的方阵。
代码如下:
void Deleteij(int M[][10],int n,int row,int col,int submat[][10])
{//n阶方阵M除去第row行第col列元素后,形成(n-1)阶的矩阵submat
int subrow=0,subcol=0;
for(int i=0;i<n;i++)
{
if(i==row) continue;//第i行自动跳过
for(int j=0;j<n;j++)
{
if(j!=col)
{
submat[subrow][subcol]=M[i][j];
subcol++;
if(subcol==n-1)
{
subrow++;
subcol=0;
}
}
}
}
}
二、求方阵M的行列式
求伴随矩阵时要多次求代数余子式,而求代数余子式就是求行列式并判断符号。根据行列式的定义,可以写递归函数来求。当阶数n==2或n==1时,直接叉乘。当n>=3时,直接按照第一行展开求和。按第一行展开的好处是,对于去掉对应的行列后求到的行列式后变号,第一个是变正的,第二个是变负的,交替变号。代码如下
int Determinant(int M[][10],int n)
{//计算方阵M的行列式
if(n==1) return M[0][0];
else if(n==2) return M[0][0]*M[1][1]-M[0][1]*M[1][0];
int sign=1;
int sum=0;
//每次都按第一行展开
for(int i=0;i<n;i++)
{//先得到除去第一行第i列的方阵
int submat[9][10];
Deleteij(M,n,0,i,submat);
//计算M[0][i]乘以它的代数余子式
sum+=sign*M[0][i]*Determinant(submat,n-1);
sign*=-1;
}
return sum;
}
三:求代数余子式。
遍历方阵求出每个元素对称位置对应的代数余子式即可(注意是对称位置的代数余子式)代码如下。
void Adjoint_matrix(int A[][10],int n,int Adj[][10])
{
for(int i=0;i<n;i++)
{
for(int j=0;j<n;j++)
{
//int sign=(i+j%2==0)?1:-1;
int sign=((i+j)%2==0)?1:-1;//不要写成了(i+j%2);
int submat[10][10];
Deleteij(A,n,i,j,submat);
Adj[j][i]=sign*Determinant(submat,n-1);
}
}
}
完整代码+运行结果:
#include<iostream>
using namespace std;
void GetMat(int *n,int M[][10]);
void Show_Mat(int M[][10],int n);
void Deleteij(int M[][10],int n,int row,int col,int submat[][10]);
int Determinant(int M[][10],int n);
void f(int M[][10],int n);
void Adjoint_matrix(int A[][10],int n,int Adj[][10]);
int main()
{
int A[10][10];
int Adj[10][10];
int n;
GetMat(&n,A);
// int d=Determinant(A,n);
// cout<<d;
// f(A,n);
Adjoint_matrix(A,n,Adj);
cout<<"方阵A的伴随矩阵为:\n";
Show_Mat(Adj,n);
}
void GetMat(int *n,int M[][10])
{
cout<<"请输入方阵的阶数:";
cin>>*n;
cout<<"输入方阵的值:\n";
for(int i=0;i<*n;i++)
for(int j=0;j<*n;j++)
cin>>M[i][j];
}
void Show_Mat(int M[][10],int n)
{
for(int i=0;i<n;i++)
{
cout<<"|";
for(int j=0;j<n;j++)
{
cout<<" "<<M[i][j];
}
cout<<" |\n";
}
}
void Deleteij(int M[][10],int n,int row,int col,int submat[][10])
{//n阶方阵M除去第row行第col列元素后,形成(n-1)阶的矩阵submat
int subrow=0,subcol=0;
for(int i=0;i<n;i++)
{
if(i==row) continue;
for(int j=0;j<n;j++)
{
if(j!=col)
{
submat[subrow][subcol]=M[i][j];
subcol++;
if(subcol==n-1)
{
subrow++;
subcol=0;
}
}
}
}
}
int Determinant(int M[][10],int n)
{//计算方阵M的行列式
if(n==1) return M[0][0];
else if(n==2) return M[0][0]*M[1][1]-M[0][1]*M[1][0];
int sign=1;
int sum=0;
//每次都按第一行展开
for(int i=0;i<n;i++)
{//先得到除去第一行第i列的方阵
int submat[9][10];
Deleteij(M,n,0,i,submat);
//计算M[0][i]乘以它的代数余子式
sum+=sign*M[0][i]*Determinant(submat,n-1);
sign*=-1;
}
return sum;
}
void f(int M[][10],int n)
{//验证除去某一行某一列后的方阵是否正确,因为devc++很难调试,所以我用这个函数辅助调试
for(int i=0;i<n;i++)
{//先得到除去第一行第i列的方阵
int subrow=0,subcol=0;
int submat[9][10];
for(int j=1;j<n;j++)
{
for(int k=0;k<n;k++)
{
if(k!=i)
{
submat[subrow][subcol]=M[j][k];
subcol++;
if(subcol==n-1)
subcol=0,subrow++;
}
}
}
cout<<"除去第1行第"<<i+1<<"列后的代数余子式:\n";
for(int j=0;j<subrow;j++)
{
cout<<"| ";
for(int k=0;k<n-1;k++)
{
cout<<submat[j][k]<<" ";
}
cout<<" |"<<endl;
}
}
}
void Adjoint_matrix(int A[][10],int n,int Adj[][10])
{
for(int i=0;i<n;i++)
{
for(int j=0;j<n;j++)
{
//int sign=(i+j%2==0)?1:-1;
int sign=((i+j)%2==0)?1:-1;//不要写成了(i+j%2);
int submat[10][10];
Deleteij(A,n,i,j,submat);
Adj[j][i]=sign*Determinant(submat,n-1);
}
}
}
测试:(觉得输出丑的可以自己改一下格式)