疫情期间,网络教学,真不是为难学生,只是担心少数学生偷懒抄作业,所以需要随机出一些题让学生学会手工计算,题还不能太难。
我为每一位同学都随机出了一套计算题,有计算行列式、伴随矩阵、矩阵乘积、化行最简形、求逆矩阵、写线性方程组的通解、求矩阵特征值及对
应特征向量组成的矩阵;让学生按固定格式提交所算出的数,当然出题时我也得调用计算函数输出每位同学对应题目的答案,好批量给分。
遇到这样的问题,求逆矩阵,得找有逆且逆矩阵也是由简单整数组成的矩阵;求特征值特征向量问题时,所求得数值也需要尽可能简单。
以下程序实现是实现这一需求的核心程序。
#include "stdafx.h"
#include <math.h>
#include <stdlib.h>
#include <time.h>
//打印一个矩阵
void print_matrix(double *A,int m,int n)
{int i,j;
for(i=0;i<m;i++)
{ for(j=0;j<n;j++)
printf("%8.3lf ",A[i*n+j]);
printf("n");
}
}
//矩阵乘
void product_matrix(double *A,double *B,double *C,int m,int s,int n)
{int i,j,k;
for(i=0;i<m*n;i++) C[i]=0;
for(i=0;i<m;i++)
for(j=0;j<n;j++)
for(k=0;k<s;k++)
C[i*n+j]=C[i*n+j]+A[i*s+k]*B[k*n+j];
}
//递归法求行列式
double det(double *A,int n)
{ if(n==1)
return A[0];
else
{ double s=0; int f=-1,k,i,j;
double *A1k=new double [(n-1)*(n-1)];
for(k=0;k<n;k++)
{ for(i=1;i<n;i++)
for(j=0;j<n;j++)
{ if(j<k)
A1k[(i-1)*(n-1)+j]=A[i*n+j];
else if(j>k)
A1k[(i-1)*(n-1)+(j-1)]=A[i*n+j];
}
f=-f;
s=s+f*A[0*n+k]*det(A1k,n-1);
}
delete [] A1k;
return s;
}
}
//化行最简,记得写这段程序是挺费劲
void ReducedRowEchelonForm(double *B,double *C,int m,int n)
{int i,j,r,c;
double p1,temp;
for(i=0;i<m*n;i++)C[i]=B[i];//C为RREF
c=0;
for(r=0;r<m;r++)
{ if(fabs(C[r*n+c])<0.000001)
{ for(i=r+1;i<m;i++)//找非0元
if(fabs(C[i*n+c])>0.000001) break;
if(i<m)
for(j=c;j<n;j++) //对换行
{temp=C[r*n+j]; C[r*n+j]=C[i*n+j]; C[i*n+j]=temp; }
}
p1=C[r*n+c];//主元位置
if(fabs(p1)>0.000001)
{ for(j=c;j<n;j++)
C[r*n+j]=C[r*n+j]/p1;//化首1元
for(i=0;i<m;i++)
{ if(i==r)continue;
p1=C[i*n+c];
for(j=c;j<n;j++) //倍加消主元上下方元素
C[i*n+j]=C[i*n+j]-p1*C[r*n+j];
}
}
else
{r=r-1;}//列全为零,保持在原行,仅列右移
c=c+1;
}
}
//求逆矩阵,用的是化行最简的方法,以前也写了求邻接矩阵的方法
int inverse_RREF(double *A,double *Ainv,int n)
{ double *AE=new double [n*n*2];
double *AE_C=new double [n*n*2];
int i,j;
for(i=0;i<n;i++)
for(j=0;j<n;j++)
{AE[i*n*2+j]=A[i*n+j];
AE[i*n*2+j+n]=0;
}
for(i=0;i<n;i++)
AE[i*n*2+i+n]=1;
ReducedRowEchelonForm(AE,AE_C,n,n*2);
for(i=0;i<n;i++)
for(j=0;j<n;j++)
{Ainv[i*n+j]=AE_C[i*n*2+j+n];
}
delete [] AE,AE_C;
return 1;
}
//这是本博文的核心,其实还是靠穷举
void able_inverse_matrix3(double *A)
{
//A是一维的,生成9乘Nc=900个数,每9个数是1,2,-1或1开头的可逆阵
int i1,i2,i3,i4,i5,i6,i7,i8,i9;
int i, f=0;
double P[9],Pv[9];
for(i1=-1;i1<3;i1++)
for(i2=-1;i2<3;i2++)
for(i3=-1;i3<3;i3++)
for(i4=-1;i4<3;i4++)
for(i5=-1;i5<3;i5++)
for(i6=-1;i6<3;i6++)
for(i7=-1;i7<3;i7++)
for(i8=-1;i8<3;i8++)
for(i9=-1;i9<3;i9++)
{P[0]=i1;P[1]=i2;P[2]=i3;P[3]=i4;P[4]=i5;P[5]=i6;P[6]=i7;P[7]=i8;P[8]=i9;
if (det(P,3)==0)
;
else
{inverse_RREF(P,Pv,3);
if( (Pv[0]-(int)Pv[0])==0
&& (Pv[1]-(int)Pv[1])==0
&& (Pv[2]-(int)Pv[2])==0
&& (Pv[3]-(int)Pv[3])==0
&& (Pv[4]-(int)Pv[4])==0
&& (Pv[5]-(int)Pv[5])==0
&& (Pv[6]-(int)Pv[6])==0
&& (Pv[7]-(int)Pv[7])==0
&& (Pv[8]-(int)Pv[8])==0
&&(P[0]==1) &&(P[1]==2) &&(P[2]==-1||P[2]==1) )//=897
{for(i=0;i<9;i++)A[i+f]=P[i];
f=f+9;
}
}
}
}
//测试函数,打出一个可逆矩阵,和手工计算求出的特征值特征向量也是整数的矩阵
void LinearAlgebra_test0701()
{ double P[9*900];//实际897个
double A[9],B[9],C[9],D[9],F[9];
int i,rd;
srand((unsigned)time(NULL));
rd=rand()%897;
able_inverse_matrix3(P);
for(i=0;i<9;i++)A[i]=P[rd*9+i];
print_matrix(A,3,3);
printf("n");
//特征值选-1,1,第三个随机。特征向量也取自整数可逆矩阵
C[0]=-1; C[1]=0.; C[2]=0.;
C[3]=0.; C[4]=1 ; C[5]=0.;
C[6]=0.; C[7]=0.; C[8]=rand()%2+2;
rd=rand()%897;
for(i=0;i<9;i++)B[i]=P[rd*9+i];
product_matrix(B,C,D,3,3,3);
inverse_RREF(B,F,3);
product_matrix(D,F,A,3,3,3);
print_matrix(A,3,3);
}
int main(int argc, char* argv[])
{
LinearAlgebra_test0701();
return 0;
}
结果:
1.000 2.000 1.000
-1.000 2.000 2.000
-1.000 1.000 1.000
-5.000 4.000 -4.000
-8.000 7.000 -4.000
0.000 0.000 1.000
Press any key to continue
试卷举例:
=====试卷编号1800001
Linear Algebra Test 2020_05
Student number:___________ Name:___________
Student number:__18052288_ Name:___张三__
1.计算下列矩阵的行列式:
┌ ┐
0 -1 0
1 -1 -1
0 1 1
└ ┚
┌ ┐
2 0 2
3 2 -1
0 2 -2
└ ┚
3.求下列两矩阵的乘积
┌ ┐
-2 -2 -2 3
-2 -1 -2 0
-2 0 0 -1
└ ┚
┌ ┐
0 0
1 3
0 3
-2 2
└ ┚
4.把下列矩阵化为行最简形,并写出其秩=____.
┌ ┐
1 2 1 2 -2
-1 -1 0 3 -2
0 2 1 0 0
└ ┚
┌ ┐
1 2 1
-1 -1 -1
1 2 2
└ ┚
请化为行最简形,并写出其通解.
┌ ┐
1 2 -1 1 2
0 1 0 3 3
2 1 -1 2 -2
└ ┚
┌ ┐
-2 -1 -5
5 4 7
-1 -1 0
└ ┚
=====1==
{为了不和html冲突,文中的<>号用全角字符替换}