一.矩阵的基本运算
加减法:直接进行加减法即可
乘法:对每一行和每一列取乘积和
转置:将矩阵倒置并逆时针旋转90度
二.矩阵的初等变换
1.两行(列)互换
2.某行(列)乘上非零系数
3.某行(列)乘上常数后加到另一行(列)上
三.经典应用
1.求A到B,恰好经过k个点的路径数量
HDU2157
代码:
#include<bits/stdc++.h> #define ll long long using namespace std; const int N = 39+7,mod = 1e3; int n,m,T; struct matrix{ll mat[N][N];}; matrix operator *(const matrix &a,const matrix &b){matrix c;memset(c.mat,0,sizeof(c.mat));for(int i=1;i<=n;i++){for(int j=1;j<=n;j++){for(int k=1;k<=n;k++){c.mat[i][j]=(c.mat[i][j]+a.mat[i][k]*b.mat[k][j])%mod;}}}return c; } matrix quickPow(matrix a,ll b){matrix ans;memset(ans.mat,0,sizeof(ans.mat));for(int i=1;i<=n;i++)ans.mat[i][i]=1;while(b){if(b&1)ans=ans*a;a=a*a;b>>=1;}return ans; } int main(){while(cin>>n>>m){if(!n&&!m)break;matrix a;memset(a.mat,0,sizeof(a.mat));for(int i=1;i<=m;i++){int x,y;cin>>x>>y;x++,y++;a.mat[x][y]=1;}cin>>T;while(T--){int x,y,k;cin>>x>>y>>k;x++,y++;matrix p=quickPow(a,k);cout<<p.mat[x][y]<<'\n';}} return 0; }
技巧:巧妙的运用了矩阵乘法的运算,将其转化为计算路径条数的方式
2.给定矩阵A,求A + A^2 + A^3 + … + A^k的结果
POJ3233
代码:
#include<iostream> #include<algorithm> #include<cstdio> #include<cstring> #include<cmath> #define ll long long using namespace std; const int N = 39+7; int n,mod,k; struct matrix{ll mat[N][N];}a; matrix operator *(const matrix &a,const matrix &b){matrix c;memset(c.mat,0,sizeof(c.mat));for(int i=1;i<=n;i++){for(int j=1;j<=n;j++){for(int k=1;k<=n;k++){c.mat[i][j]=(c.mat[i][j]+a.mat[i][k]*b.mat[k][j])%mod;}}}return c; } matrix operator +(const matrix &a,const matrix &b){matrix c;memset(c.mat,0,sizeof(c.mat));for(int i=0;i<N;i++){for(int j=0;j<N;j++){c.mat[i][j]=(a.mat[i][j]+b.mat[i][j])%mod;}}return c; } matrix quickPow(matrix a,ll b){matrix ans;memset(ans.mat,0,sizeof(ans.mat));for(int i=1;i<=n;i++)ans.mat[i][i]=1;while(b){if(b&1)ans=ans*a;a=a*a;b>>=1;}return ans; } matrix solve(int k){if(k==1)return a;if(k%2==1){matrix pp=solve(k/2);matrix qq=quickPow(a,k); matrix ans=pp+quickPow(a,k/2)*pp+qq;return ans;}matrix pp=solve(k/2);matrix ans=pp+(quickPow(a,k/2)*pp);return ans; } int main(){cin>>n>>k>>mod;for(int i=1;i<=n;i++){for(int j=1;j<=n;j++){cin>>a.mat[i][j];}} matrix p=solve(k);for(int i=1;i<=n;i++){for(int j=1;j<=n;j++){cout<<p.mat[i][j]<<' ';}puts("");}return 0; }
技巧:运用分治和矩阵的分配律,在O(logk)的复杂度内求解完问题
3.给定n和p,求第n个Fibonacci数mod p的值,n不超过2^63
代码:
#include<bits/stdc++.h> #define ll long long using namespace std; const int N = 3,mod = 1e9+7; struct matrix{ll mat[N][N];}; matrix operator *(const matrix &a,const matrix &b){matrix c;memset(c.mat,0,sizeof(c.mat));for(int i=1;i<N;i++){for(int j=1;j<N;j++){for(int k=1;k<N;k++){c.mat[i][j]=(c.mat[i][j]+a.mat[i][k]*b.mat[k][j])%mod;}}}return c; } matrix quickPow(matrix a,ll b){matrix ans;memset(ans.mat,0,sizeof(ans.mat));for(int i=1;i<N;i++)ans.mat[i][i]=1;while(b){if(b&1)ans=ans*a;a=a*a;b>>=1;}return ans; } int main(){ll n;cin>>n;if(n<=2){cout<<1<<'\n';return 0;}matrix a;memset(a.mat,0,sizeof(a.mat));a.mat[1][1]=a.mat[1][2]=1;matrix p;memset(p.mat,0,sizeof(p.mat));p.mat[1][1]=p.mat[1][2]=p.mat[2][1]=1;a=a*quickPow(p,n-2);cout<<a.mat[1][1]<<'\n';return 0; }
技巧:巧妙地使用矩阵快速幂加速递推,复杂度O(logn)
4.给定一个递推式,要求在O(logn)复杂度内求解
代码:
#include<bits/stdc++.h> #define ll long long using namespace std; const int N = 4,mod = 1e9+7; struct matrix{ll mat[N][N];}; matrix operator *(const matrix &a,const matrix &b){matrix c;memset(c.mat,0,sizeof(c.mat));for(int i=1;i<N;i++){for(int j=1;j<N;j++){for(int k=1;k<N;k++){c.mat[i][j]=(c.mat[i][j]+a.mat[i][k]*b.mat[k][j])%mod;}}}return c; } matrix quickPow(matrix a,ll b){matrix ans;memset(ans.mat,0,sizeof(ans.mat));for(int i=1;i<N;i++)ans.mat[i][i]=1;while(b){if(b&1)ans=ans*a;a=a*a;b>>=1;}return ans; } int main(){int T;cin>>T;while(T--){int n;cin>>n;if(n<=3){cout<<1<<'\n';continue;}matrix a;memset(a.mat,0,sizeof(a.mat));a.mat[1][1]=a.mat[1][2]=a.mat[1][3]=1;matrix p;memset(p.mat,0,sizeof(p.mat));p.mat[1][1]=p.mat[1][3]=p.mat[2][1]=p.mat[3][2]=1;a=a*quickPow(p,n-3);cout<<a.mat[1][1]<<'\n';}return 0; }
技巧:和斐波那契数列一样,巧妙地使用矩阵快速幂加速递推,复杂度O(logn)
5.高斯消元
代码:
#include<bits/stdc++.h> #define ll long long using namespace std; const int N = 1e2+39+7; int n;double a[N][N]; int gauss(){for(int i=1;i<=n;i++){int r=n+1;for(int j=i;j<=n;j++)if(fabs(a[j][i])>fabs(a[(r==n+1?0:r)][i]))r=j;if(r==n+1)return -1;// int r=i; // for(int j=i+1;j<=n;j++)if(fabs(a[j][i])>fabs(a[r][i]))r=j; // cout<<i<<' '<<r<<'\n';for(int j=1;j<=n+1;j++)swap(a[i][j],a[r][j]);if(fabs(a[i][i])<(1e-7))return 0;for(int j=n+1;j>=1;j--)a[i][j]/=a[i][i];for(int j=1;j<=n;j++){if(i==j)continue;double m=a[j][i]/a[i][i];for(int k=1;k<=n+1;k++)a[j][k]-=a[i][k]*m;}}return 1; } int main(){cin>>n;for(int i=1;i<=n+1;i++)a[0][i]=0;for(int i=1;i<=n;i++){for(int j=1;j<=n+1;j++){cin>>a[i][j];}}int k=gauss();if(k==1)for(int i=1;i<=n;i++)printf("x%d=%.2lf\n",i,a[i][n+1]);else if(k==-1)cout<<"0";else cout<<"-1";return 0; }
技巧:通过矩阵的初等变换,通过尝试解来推测出每个未知数,复杂度O(n^3)
6.点的变换
代码:
#include<bits/stdc++.h> #define ll long long using namespace std; const int N = 39+7,mod = 1e3; int n,m,T; struct matrix{ll mat[N][N];}a[N]; matrix operator *(const matrix &a,const matrix &b){matrix c;memset(c.mat,0,sizeof(c.mat));for(int i=1;i<=n;i++){for(int j=1;j<=n;j++){for(int k=1;k<=n;k++){c.mat[i][j]=(c.mat[i][j]+a.mat[i][k]*b.mat[k][j])%mod;}}}return c; } int main(){cin>>n>>m;for(int i=1;i<=n;i++){int x,y;cin>>x>>y;a[i].mat[1][1]=x;a[i].mat[1][2]=x;}for(int i=1;i<=m;i++){int op,p,q,x;cin>>op>>x;if(op==1){cin>>p>>q;matrix k;memset(k.mat,0,sizeof(k.mat));k.mat[1][1]=k.mat[2][2]=k.mat[3][3]=1;k.mat[1][3]=p;k.mat[2][3]=q;matrix ans=k*a[x];cout<<ans.mat[1][1]<<' '<<ans.mat[1][2]<<'\n'; }else if(op==2){cin>>p;matrix k;memset(k.mat,0,sizeof(k.mat));k.mat[1][1]=k.mat[2][2]=p;k.mat[3][3]=1;matrix ans=k*a[x];cout<<ans.mat[1][1]<<' '<<ans.mat[1][2]<<'\n'; }else if(op==3){matrix k;memset(k.mat,0,sizeof(k.mat));k.mat[2][2]=-1;k.mat[1][1]=k.mat[3][3]=1;matrix ans=k*a[x];cout<<ans.mat[1][1]<<' '<<ans.mat[1][2]<<'\n'; }else if(op==4){matrix k;memset(k.mat,0,sizeof(k.mat));k.mat[1][1]=-1;k.mat[2][2]=k.mat[3][3]=1;matrix ans=k*a[x];cout<<ans.mat[1][1]<<' '<<ans.mat[1][2]<<'\n'; }}return 0; }
技巧:通过矩阵乘法,巧妙地将点的一些操作变化为矩阵的运算