矩阵快速幂模版:

快速幂的模版在这里不再赘述。由线性代数的知识可以知道,当俩个矩阵满足n*p,p*m时可以进行计算。具体如下:

image

因此,我们可以暴力这个过程:对于新矩阵的位置i,j来说,枚举所有的k,对(i,k)*(k,j)求和,就是该位置的值。时间复杂度是O(n^3)的

矩阵讲完了,我们再讲讲矩阵快速幂,首先,矩阵可以看做是一个状态,而矩阵的几次方可以看作是多种状态的叠加,但是每个状态叠加时的计算过程是一致的,一般上称作矩阵乘(*)如果一个一个去计算矩阵的幂,就会让时间复杂度达到O(k),而矩阵快速幂就是通过二进制分解幂指数来将时间复杂度降到O(logk);所以总时间复杂度O(n^3*logk)

这里还有个常数优化,就是ijk的枚举顺序,可以先i后k后j可以优化掉访问内存时的一个常数。具体原因参考《计算机组成原理》

变式:广义矩阵

26南昌ICPC全国邀请赛C题

题意不再赘述。首先,我们把修建天数作为边权,而最先已经修建好的道路,边权均为0.不要忘记重边。

在做这题时我们要注意一个特殊点:n<=200.这个地方其实在给一定的提示:这不一定是一道纯图论题,可以是dfs,dp,甚至暴力模拟。因此这时我们的思路也不能再局限于如何在O(n^2)的时间复杂度内求解,即不用局限于一定要用图论相关的内容求解。附:本题思路如果是第一次做基本都看不出来。

本题的话是从邻接矩阵建图为切入点的,当我们用邻接矩阵记录下样例的第一个状态(初始化为正无穷):

image

这是只走一步时的状态矩阵,当我们走第二步时,我们可以列出:

image

观察俩步的状态矩阵,会发现原本从i到j只需要1步,而现在需要在中间多经过一个点k,即从i到k,再从k到j。因此第二个矩阵中对应的值就为min(A1(i,k),A1(k,j)).进一步推广到更高次幂的状态,会发现:

A3可以由A1和A2推出,值可以为max(A1(i,k),A2(k,j))或max(A2(i,k),A1(k,j));A4的矩阵可以由A3和A1推出,也可以由俩个A2推出...

以此类推,会发现,走w步实际上就是矩阵为w次幂时的状态,因此我们只需要求取w状态的矩阵即可在O(1)的复杂度下得出答案。而本题计算矩阵乘时是利用第三者点k来跳跃的,因此运算方式不再是一般的矩阵乘,而是取max,代码如下:

代码
#include<bits/stdc++.h>
using namespace std;
#define int long long
#define ull unsigned long long
const int N=205;
const int INF=1e9;
int n,m,k,q,w;
struct pi{
    int a[N][N];
    pi(){
        for(int i=1;i<=n;i++){
            for(int j=1;j<=n;j++)a[i][j]=INF;
        }
    }
};
pi operator*(pi x,pi y){
    pi t;
    for(int i=1;i<=n;i++){
        for(int j=1;j<=n;j++){
            for(int k=1;k<=n;k++){
                t.a[i][j]=min(t.a[i][j],max(x.a[i][k],y.a[k][j]));
            }
        }
    }
    return t;
}

pi pq(pi A,int k){
    pi res=A;
    k--;
    while(k){
        if(k&1)res=res*A;
        A=A*A;
        k>>=1;
    }
    return res;
}
void solve(){
    cin>>n>>m;
    pi A;
    for(int i=1;i<=m;i++){
        int u,v;cin>>u>>v;
        A.a[u][v]=0;
    }
    cin>>k;
    for(int i=1;i<=k;i++){
        int u,v;cin>>u>>v;
        A.a[u][v]=min(A.a[u][v],i);
    }
    cin>>q>>w;
    pi ans=pq(A,w);
    int st,ed;
    for(int i=1;i<=q;i++){
        cin>>st>>ed;
        int x=ans.a[st][ed];
        if(x!=INF)cout<<x<<'\n';
        else cout<<"-1\n";
    }
}
signed main(){
    ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);
    int _=1;
    //cin>>_;
    while(_--)solve();
}
posted on 2026-05-24 22:19  LeoCodex  阅读(5)  评论(0)    收藏  举报