矩阵操作
信息竞赛中矩阵的应用看似没用不过在实际应用中却能发挥很大的作用(可以把一些一维递推优化到log(n),还可以求路径方案等),在这里把矩阵的各种操作进行一下总结。
大体上说,矩阵操作有5种
- 矩阵乘数
- 矩阵的幂
- 矩阵加法
- 矩阵叉乘
- 矩阵点乘
矩阵乘法具体怎么做应该都清楚,在这里也说不太清楚
上两个小图:
基本性质
1.结合性 (AB)C=A(BC).
2.对加法的分配性 (A+B)C=AC+BC,C(A+B)=CA+CB .
3.对数乘的结合性 k(AB)=(kA)B =A(kB).
4.关于转置 (AB)’=B’A’.
几种操作:
1.矩阵乘数:
n*m 的矩阵,每一位都乘 t 即使新的矩阵
2.矩阵的幂
用“快速幂”的思想,只是把x^y中的x换成矩阵而已,最好用一个结构体表示,这样结构会比较清晰。
如:最基本的用矩阵快速幂加速递推求斐波那契数列。
3.矩阵加法
前提是必须为两个大小相同的矩阵,对应位数相加得到新的矩阵
4.矩阵叉乘
正常的矩阵乘法
注: n * m 与 p * q 则 m==p
5.矩阵点乘
矩阵点乘与加法类似,同样要求必须大小相同,对应相乘即可。
一道小题:
Description:
作业中矩阵的操作有5种:
*矩阵乘数
^矩阵的幂
+矩阵加法
X矩阵叉乘
.矩阵点乘
现需要你输出对应操作后的结果
Input
第一行为两个整数,矩阵A的行n 和 列m。
第2~n+1行 每行有m个整数,整数与整数间用空格间隔,对应着矩阵A的n*m个元素。
第n+2行 一个操作符,(* ^ + X .)分别代表矩阵乘整数、矩阵幂运算、矩阵加法、矩阵叉乘、矩阵点乘
如果操作符是* 第n+3行为一个整数λ,计算λA
如果操作符是^第n+3行为一个整数e,计算Ae
如果是(+、X、.)则从第n+3行开始,是矩阵B的数据,同矩阵A的数据格式,计算A+B、AXB、A.B
Output
结果按矩阵的行列输出矩阵
Sample Input
2 2
1 1
2 0
X
2 3
0 2 3
1 1 2
Sample Output
1 3 5
0 4 6
HINT
数据保证合法
答案和所有运算的中间过程,保证不爆int
Code:
#include<stdio.h>
#include<string.h>
struct matrix
{
int a[100][100];
}v,ans,origin;
int n,m;
int is[100][100];
void init()
{
memset(ans.a,0,sizeof(ans.a));
for(int i=0;i<n;i++)
{
for(int j=0;j<m;j++)
{
if(i==j)
ans.a[i][j]=1;
else ans.a[i][j]=0;
}
}
}
matrix mul(matrix x,matrix y)
{
matrix tmp;
memset(tmp.a,0,sizeof(tmp.a));
for(int i=0;i<n;i++)
{
for(int j=0;j<n;j++)
{
for(int k=0;k<n;k++)
{
tmp.a[i][j]+=(x.a[i][k]*y.a[k][j]);
}
}
}
return tmp;
}
void cal(int n)
{
while(n)
{
if(n&1)
{
ans=mul(ans,origin);
}
n>>=1;
origin=mul(origin,origin);
}
}
int main()
{
scanf("%d%d",&n,&m);
for(int i=0;i<n;i++)
{
for(int j=0;j<m;j++)
{
scanf("%d",&ans.a[i][j]);
}
}
char s[3];
scanf("%s",s);
if(s[0]=='*')
{
int t;
scanf("%d",&t);
for(int i=0;i<n;i++)
{
for(int j=0;j<m;j++)
{
if(j==m-1)
{
printf("%d",ans.a[i][j]*t);
}
else
printf("%d ",ans.a[i][j]*t);
}
printf("\n");
}
}
if(s[0]=='^')
{
int t;
scanf("%d",&t);
for(int i=0;i<n;i++)
{
for(int j=0;j<m;j++)
{
origin.a[i][j]=ans.a[i][j];
}
}
init();
cal(t);
for(int i=0;i<n;i++)
{
for(int j=0;j<m;j++)
{
if(j==m-1)
{
printf("%d",ans.a[i][j]);
}
else
printf("%d ",ans.a[i][j]);
}
printf("\n");
}
}
if(s[0]=='+')
{
int p,q;
scanf("%d%d",&p,&q);
for(int i=0;i<p;i++)
{
for(int j=0;j<q;j++)
{
scanf("%d",&is[i][j]);
}
}
for(int i=0;i<n;i++)
{
for(int j=0;j<m;j++)
{
if(j==m-1)
{
printf("%d",ans.a[i][j]+is[i][j]);
}
else
printf("%d ",ans.a[i][j]+is[i][j]);
}
printf("\n");
}
}
if(s[0]=='X')
{
int p,q;
scanf("%d%d",&p,&q);
for(int i=0;i<p;i++)
{
for(int j=0;j<q;j++)
{
scanf("%d",&v.a[i][j]);
}
}
matrix tmp;
memset(tmp.a,0,sizeof(tmp.a));
for(int i=0;i<n;i++)
{
for(int j=0;j<q;j++)
{
for(int k=0;k<m;k++)
{
tmp.a[i][j]+=(ans.a[i][k]*v.a[k][j]);
}
}
}
for(int i=0;i<n;i++)
{
for(int j=0;j<q;j++)
{
if(j==q-1)
{
printf("%d",tmp.a[i][j]);
}
else
printf("%d ",tmp.a[i][j]);
}
printf("\n");
}
}
if(s[0]=='.')
{
int p,q;
scanf("%d%d",&p,&q);
for(int i=0;i<p;i++)
{
for(int j=0;j<q;j++)
{
scanf("%d",&is[i][j]);
}
}
for(int i=0;i<n;i++)
{
for(int j=0;j<m;j++)
{
if(j==m-1)
{
printf("%d",ans.a[i][j]*is[i][j]);
}
else
printf("%d ",ans.a[i][j]*is[i][j]);
}
printf("\n");
}
}
return 0;
}
矩阵乘法的时间复杂度是O(n^3),但可以用分治的方法进行优化。
如,A^n