7阶方阵a的伴随矩阵求解方法与计算步骤详解
7.5 数组的应用
前面几节,我们介绍了一维数组、二维数组、字符串的定义和使用。本节主要通过几个数组程序设计的实际应用场景实例进一步掌握数组的应用。相关实例,对于计算机问题求解具有启发作用
例1:某校要调查学生对该校的10个社团的受欢迎情况,共调查了n位学生,要求每位学生最多只能选择1个社团投票(不选表示弃权,多选为废票)。请编写程序统计每个社团的投票情况。投票表格如下:
学生拿到票后,在喜欢的社团前面数字打勾。如喜欢“信息社”,在“1.信息社”中的“1”处打勾。计票小组把每个投票的编号依次记录下来,如果是弃权票,则记0,如果是废票则记-1,如果数字在-1至10之外,则为错误输入。如以下输入:
10
1 2 3 -1 5 0 2 1 2输出为每行五个社团,最后是各类票情况,如:
信息社 3;动漫社2;文学社1;诗社0; 蓝球社1;
读书社 0;电子社0;英语社0;礼仪社0;书法社0
有效票:8;弃权:1;废票:1;错误输入:0这是一道非常实用的题目。我们采用IPO分析方法和自顶向下的程序设计方法实现程序。根据输入、输出和处理,不难得到求解问题的伪代码:
int main( )
{
(1)输入n;
(2)i从0至n变化,重复以下n次
(a)输入1个学生的投票x
(b)x是有效票,则把该票对应的社团加1票
(c)x是无效票,则相应类别无效票加1票
(4)按每行5个社团输出每个社团得票
(5)输出四类票的情况
}先来确定输入。因为回收票数要由键盘输入,可设变量n保存回收的票数。接下来要输入和处理n个投票结果,由于是每输入一张票的结果,马上要进行处理,处理完后该结果即丢弃,因此不必要定义数组保存所有投票,可用一个变量choice保存每次输入的结果。由于10个社团是预先知道的,不需要从键上输入,只需要在程序直接定义就可以了。其中,二维数组assn把社团名称保存在行下标为1至10的行中(一维数组),行下标0、11、12分别保存非有效票类别。因此相关变量定义如下:
int n;
int choice;
char assn[13][20]={"弃权票","信息社","动漫社","文学社","诗社","蓝球社","读书社","电子社","英语社","礼仪社","书法社","废票","错误票"};确定处理。本例要处理的票的类别有有效票、弃权票、废票和错误票四类,其中有效票又根据不同的社团分10类,所以总类别为13类,我们可以定义13个不同的变量保存每个类别的票数,但这样计算会很困难。为此,我们把13个类别用一个一维数组poll表示,与数组assn对应,用下标来表示不同的类别,下标1至10依次对应从“信息社”到“书法社”等十个社团,下标0、11、12分别表示弃权票等无效票。数组的初值都设为0。
int poll[13]={0};要根据每张票的choice来选择哪类加1,因此可用if_else构成的多分支选择或switch语句来实现,如果用if_else语句,则代码为:
scanf("%d",&choice);
if(choice==1) choice[1]++;
else if(choice==2) poll[2]++;
else if(choice==3) poll[3]++;
else if(choice==4) poll[4]++;
else if(choice==5) poll[5]++;
else if(choice==6) poll[6]++;
else if(choice==7) poll[7]++;
else if(choice==8) poll[8]++;
else if(choice==9) poll[9]++;
else if(choice==10) poll[10]++;
else if(choice==0) poll[0]++;
else if(choice==-1)poll[11]++;
else poll[12]++;如果用switch来实现,代码为:
scanf("%d",&choice);
switch(choice){
case 1:poll[1]++;break;
case 2:poll[2]++;break;
case 3:poll[3]++;break;
case 4:poll[4]++;break;
case 5:poll[5]++;break;
case 6:poll[6]++;break;
case 7:poll[7]++;break;
case 8:poll[1]++;break;
case 9:poll[9]++;break;
case 10:poll[10]++;break;
case 0:poll[0]++;break;
case -1:poll[11]++;break;
default:poll[12]++;break;
}从if_else和switch两组代码可以看出:除了两类特殊票外,基本上都满足choice的值为i时,让poll[i]加1,如choice为5时,让poll[5]加1。因此,我们可不必要用if_else和switch,直接让choice成为数组poll的下标就可以完成算法,最简单算法为:
scanf("%d",choice);
if(choice>=0 && choice<=10) poll[choice]++; //弃权或有效票
else if(choice==-1) poll[11]++; //废票
else poll[12]++; //错误票以上利用数组下标可变的特点改写的代码显示短得太多,您得到什么启示呢?对于n张选票的处理,只需要把上述一张选票的处理代码重复n次即可:
for(i=1;i<=n;i++)
{
scanf("%d",choice);
if(choice>=0 && choice<=10) poll[choice]++; //弃权或有效票
else if(choice==-1) poll[11]++; //废票
else poll[12]++; //错误票
}确定输出。由于要输出10个社团得票,只要用for循环依次输出poll[1]至poll[10]就行了,代码为:
for(i=1;i<=10;i++)
printf("%d;",poll[i]);但是每个社团得票之前要输出社团名,因此前面定义的数组assn的作用就发挥出来了,由于assn中的下标i代表的社团与poll中的i代表的一致,因此代码修改为:
for(i=1;i<=10;i++)
printf("%s%d",assn[i],poll[i]);由于要求每行输出5个,因此要根据i是否是5的倍数决定是否输出换行符或分号“;”,因此,代码进一步完善为:
for(i=1;i<=10;i++){
printf("%s%d",assn[i],poll[i]);
if(i%5==0)printf("\n");
else printf(";");
}最后再输出有效票和各类无效票:
printf("有效票:%d;",n-poll[0]-poll[11]-poll[12]);
printf("%s:%d;%s:%d;",assn[0],poll[0],assn[11],poll[11]);
printf("%s:%d\n",assn[12],poll[12]);通过前面解剖麻雀式讲解,现在可以得到完整程序如下:
#include
int main( )
{
int n,i;
int choice;
char assn[13][20]={"弃权票","信息社","动漫社","文学社","诗社","蓝球社","读书社","电子社","英语社","礼仪社","书法社","废票","错误票"};
int poll[13]={0};
scanf("%d",&n);
for(i=1;i<=n;i++)
{
scanf("%d",&choice);
if(choice>=0 && choice<=10) poll[choice]++; //弃权或有效票
else if(choice==-1) poll[11]++; //废票
else poll[12]++; //错误票
}
for(i=1;i<=10;i++){
printf("%s%d",assn[i],poll[i]);
if(i%5==0)printf("\n");
else printf(";");
}
printf("有效票:%d;",n-poll[0]-poll[11]-poll[12]);
printf("%s:%d;%s:%d;",assn[0],poll[0],assn[11],poll[11]);
printf("%s:%d\n",assn[12],poll[12]);
return 0;
} 例2:人工神经网络(ANN)是机器学习中非常重要的结构,由多个神经元按一定层级或方式构成,每个神经元能把多个输入映射成一个输出(如图)。
神经元的输入与输出
神经元的输入是一个向量,通过与神经元的权值运算,即后通过激活函数即可得到输出a。
现要求从键盘上输入一个具有5个分量的向量通过神经元后得到输出a。设权值向量由决定,用该神经元的偏移值b=1。
本题初看似乎很复杂,因为数据较多。但是算法却非常简单,主要是解决z的计算问题,有了z,计算a就很容易了。由于权值w已知。我们用IPO分析方法来解决此问题。
先来确定输入。由于权值w与偏移值b是已经确定的,因此不需要输入,因此本例需要输入的仅是向量x。因此可以确定变量定义为:
double x[5]; //输入向量
double w[5]={0.5,0.025,0.4,0.038,0.21}; //权值向量
double b=1; //偏移值
double z,a; //保存计算结果权向量只有5个分量,可以一个一个输入,但是当分量数更多时,这行不通,所以仍然采用一维数组的输入方法:
for(i=0;i<5;i++)
scanf("%d",&x[i]);再来看处理。处理分为两步,第一步求z,可设z的初值为0,然后从0至n依次把x[i]*w[i]的计算结果存入z中,即复复执行z=z+x[i]*w[i]。最后在z上加上b即可:
z=0;
for(i=0;i<5;i++)
z=z+x[i]*w[i];
z=z+b;第二步求输出a,直接用函数exp计算:
a=1.0/(1.0+exp(-z));最后是输出,只有一个数a,用一句printf即可:
printf("a=%f\n",a);完整的程序代码如下;
#include
int main( )
{
double x[5]; //输入向量
double w[5]={0.5,0.025,0.4,0.038,0.21}; //权值向量
double b=1,i; //偏移值
double z,a; //保存计算结果
for(i=0;i<5;i++)
scanf("%d",&x[i]);
z=0;
for(i=0;i<5;i++)
z=z+x[i]*w[i];
z=z+b;
a=1.0/(1.0+exp(-z));
printf("a=%f\n",a);
return 0;
} 我们能够计算一个神经元的输入和输出,当把很多神经元组合起来形成一个神经网络,我们也能得到整个网络的输出。
例3:求两个矩阵的乘积A*B,A为m行k列,B为k行n列。m(<=10)、k(<=10)、n(<=10)从键盘上输入,然后依次输入矩阵A和矩阵B,求A*B的结果C并输出。
矩阵乘法不仅是数学的运算,而在机器学习、图像处理等方面具有广泛应用。矩阵乘法运算是矩阵变换的基础。根据题目,我们可以写出程序伪代码如下:
#define N 10
int main( )
{
(1)输入m,n,k;
(2)输入矩阵A;
(3)输入矩阵B;
(4)求出矩阵C;
(5)输出矩阵C;
}先来确定输入。先要输入m、k、n三个变量,然后输入矩阵A和矩阵B,用已经学过的知识写出代码:
scanf("%d%d%d",&m,&k,&n);
for(i=0;i再来确定处理。矩阵乘法结果仍然是一个矩阵,一个m*k的矩阵与一个k*m的矩阵运算是一个m*n的矩阵。处理的目的是获得矩阵C的每个元素c[i][j],因此可按一般矩阵输入方法取得求C中每个元素,伪代码如下:
for(i=0;i因此,求C[i][j]成为问题求解的关键。我们先手工演示如何求C[i][j]。
A
X
B
C
C[i][j]的计算规则是把左边矩阵第i行与右边矩阵的第j列对应的元素相乘并求和。根据规则,C[0][0]和C[1][1]两个元素可如下求得:
C[0][0]=A[0][0]*B[0][0]+A[0][1]*B[1][0]+A[0][2]*B[2][0]+A[0][3]*B[3][0]
=1*1+2*2+3*3+4*0=14
...
C[1][1]=A[1][0]*B[0][1]+A[1][1]*B[1][1]+A[1][2]*B[2][1]+A[1][3]*B[3][1]
=5*0+6*1+7*5+8*6=89观察发现求c[i][j]时,A的行号固定为i,列号从0至3变化;B的行号从0至3,列号固定为j。即:
C[i][j]=A[i][0]*B[0][j]+A[i][1]*B[1][j]+A[i][2]*B[2][j]+A[i][3]*B[3][j]可见c[i][j]由很多项求和得到,而且项数与A的列数或B的行数k相等,因此,可以用“sum=sum+数据项i”写出求c[i][j]的代码为:
sum=0;
for(h=0;h把以上代码替换求矩阵C的伪代码中的“求C[i][j]放在sum中”步骤,得到完整的求矩阵C的代码:
for(i=0;i由于sum计算完后要给C[i][j]赋值,所以可以用C[i][j]直接代替sum,这样可以减少C[i][j]=sum这行代码。以上算法看起来简单,但因涉及的变量较多,分析起来不是件容易的事。而且算法涉及到了三重循环,所以编写和阅读会有一定困难。解决之道是多看多想。
最后是输出。直接用二维数组的输出模板代码即可,见完整程序。如下:
#include
#define N 10
int main( )
{
int A[N][N],B[N][N],C[N][N];
int i,j,h,m,n,k,sum;
printf("Enter m,k,n:");
scanf("%d%d%d",&m,&k,&n);
printf("Enter Matrix A:\n;");
for(i=0;i 本节通过三个实例展示了一维数组、二维数组和字符串的使用。用解剖麻雀式的方法,把每个问题的求解过程清晰展现出来。初学者经常会觉得一些较难无从下手,但是本节的分析思路有助于初学者借鉴。本节就讲到这里,下节再见!
声明:本文由"麦兜"发布,不代表"破站"立场,转载联系作者并注明出处:https://www.848586.cn/241382.html
