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

因此,我们可以暴力这个过程:对于新矩阵的位置i,j来说,枚举所有的k,对(i,k)*(k,j)求和,就是该位置的值。时间复杂度是O(n^3)的
矩阵讲完了,我们再讲讲矩阵快速幂,首先,矩阵可以看做是一个状态,而矩阵的几次方可以看作是多种状态的叠加,但是每个状态叠加时的计算过程是一致的,一般上称作矩阵乘(*)如果一个一个去计算矩阵的幂,就会让时间复杂度达到O(k),而矩阵快速幂就是通过二进制分解幂指数来将时间复杂度降到O(logk);所以总时间复杂度O(n^3*logk)
这里还有个常数优化,就是ijk的枚举顺序,可以先i后k后j可以优化掉访问内存时的一个常数。具体原因参考《计算机组成原理》
变式:广义矩阵
题意不再赘述。首先,我们把修建天数作为边权,而最先已经修建好的道路,边权均为0.不要忘记重边。
在做这题时我们要注意一个特殊点:n<=200.这个地方其实在给一定的提示:这不一定是一道纯图论题,可以是dfs,dp,甚至暴力模拟。因此这时我们的思路也不能再局限于如何在O(n^2)的时间复杂度内求解,即不用局限于一定要用图论相关的内容求解。附:本题思路如果是第一次做基本都看不出来。
本题的话是从邻接矩阵建图为切入点的,当我们用邻接矩阵记录下样例的第一个状态(初始化为正无穷):


A3可以由A1和A2推出,值可以为max(A1(i,k),A2(k,j))或max(A2(i,k),A1(k,j));A4的矩阵可以由A3和A1推出,也可以由俩个A2推出...
代码
#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();
}
浙公网安备 33010602011771号