矩阵乘法的意义与矩阵快速乘
Posted CCSU_Cola
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了矩阵乘法的意义与矩阵快速乘相关的知识,希望对你有一定的参考价值。
P3758 [TJOI2017]可乐
题面:加里敦星球的人们特别喜欢喝可乐。因而,他们的敌对星球研发出了一个可乐机器人,并且放在了加里敦星球的 1 号城市上。这个可乐机器人有三种行为: 停在原地,去下一个相邻的城市,自爆。它每一秒都会随机触发一种行为。现在给加里敦星球城市图,在第 0 秒时可乐机器人在 1 号城市,问经过了 t 秒,可乐机器人的行为方案数是多少?
思路:用矩阵表示两点之间有连线 A [ u ] [ v ] = 1 A[u][v]=1 A[u][v]=1; A k A^k Ak的第 i i i行第 j j j列的数字含义是从 i i i到 j j j经过 k k k步的路径方案总数。因为第0秒停留在1号位置,所以我们只需要将矩阵的t次幂求出来,然后加上 A [ 1 ] [ i ] A[1][i] A[1][i]即可。因为有自爆,即我们需要设置一个0号点,将1到n都连向0号点,又因为有原地停留,所以再在每个点连一个自环就可以了。
#include<bits/stdc++.h>
using namespace std;
const int mod=2017;
struct tt{
int a[32][32];
inline tt operator * (const tt xx){
tt ret;
memset(&ret,0,sizeof ret);
for(int i=0;i<=30;i++){
for(int j=0;j<=30;j++){
for(int k=0;k<=30;k++){
ret.a[i][j]+=a[i][k]*xx.a[k][j]%mod;
ret.a[i][j]%=mod;
}
}
}
return ret;
}
};
tt ksm(tt &a,int b){
tt ret;
memset(&ret,0,sizeof(ret));
for(int i=0;i<=30;i++){
ret.a[i][i]=1;
}
while(b){
if(b&1)ret=ret*a;
a=a*a;
b>>=1;
}
return ret;
}
tt mp;
int main(){
int n,m;
scanf("%d%d",&n,&m);
for(int i=1;i<=m;i++){
int x,y;
scanf("%d%d",&x,&y);
mp.a[x][y]=1;
mp.a[y][x]=1;
}
for(int i=0;i<=n;i++){
mp.a[i][i]=1;
}
for(int i=1;i<=n;i++){
mp.a[i][0]=1;
}
int ans=0;
scanf("%d",&m);
tt ret=ksm(mp,m);
for(int i=0;i<=n;i++){
ans=(ans+ret.a[1][i])%mod;
}
cout<<ans<<endl;
return 0;
}
F - Graph Smoothing
题意:有k次操作,每次操作可以选择一条边,使得边两端的数的点权等于他们的算数平均数,问k次操作后每个点权的期望值。
思路:引用大佬的博客,求得矩阵 A k A^k Ak后,矩阵 A [ u ] [ i ] A[u][i] A[u][i]即为u对i的贡献,然后只需乘上点权即可。
#include<bits/stdc++.h>
using namespace std;
#define ll long long
const ll mod=1e9+7;
struct tt{
ll a[110][110];
inline tt operator * (const tt xx){
tt ret;
memset(&ret,0,sizeof ret);
for(int i=0;i<=101;i++){
for(int j=0;j<=101;j++){
for(int k=0;k<=101;k++){
ret.a[i][j]+=a[i][k]*xx.a[k][j]%mod;
ret.a[i][j]%=mod;
}
}
}
return ret;
}
};
tt ksm(tt &a,int b){
tt ret;
memset(&ret,0,sizeof(ret));
for(int i=0;i<=101;i++){
ret.a[i][i]=1;
}
while(b){
if(b&1)ret=ret*a;
a=a*a;
b>>=1;
}
return ret;
}
ll ksmm(ll x,ll b){
ll res=1;
while(b){
if(b&1)
res=res*x%mod;
x=x*x%mod;
b>>=1;
}
return res%mod;
}
tt mp;
int d[110];
int val[110];
int a[110][110];
int main(){
int n,m,k;
scanf("%d%d%d",&n,&m,&k);
for(int i=1;i<=n;i++){
scanf("%d",&val[i]);
}
for(int i=1;i<=m;i++){
int x,y;
scanf("%d%d",&x,&y);
a[x][y]=1;
a[y][x]=1;
d[x]++;
d[y]++;
}
ll f=ksmm(m*2,mod-2);
for(int i=1;i<=n;i++){
for(int j=1;j<=n;j++){
if(a[i][j]){
mp.a[j][i]=f;
}
mp.a[i][i]=(2*m-d[i])*f%mod;
}
}
tt res=ksm(mp,k);
for(int i=1;i<=n;i++){
ll ans=0;
for(int j=1;j<=n;j++){
ans=(ans+(1ll)*res.a[j][i]*val[j])%mod;
}
printf("%lld\\n",ans);
}
}
以上是关于矩阵乘法的意义与矩阵快速乘的主要内容,如果未能解决你的问题,请参考以下文章