矩陣操作
信息競賽中矩陣的應用看似沒用不過在實際應用中卻能發揮很大的作用(可以把一些一維遞推優化到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