矩阵乘法的意义与矩阵快速乘

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);
    }
}

以上是关于矩阵乘法的意义与矩阵快速乘的主要内容,如果未能解决你的问题,请参考以下文章

Python中怎样计算3%乘100

2×3矩阵乘3×2矩阵要怎么算?

快速乘快速幂(矩阵快速幂)

动态规划 - 矩阵链乘法

如何理解矩阵相乘的几何意义或现实意义

快速幂矩阵