POJ3613 Cow Relays
题目大意
给你一个具有 \(m\) 条边的图( \(2\le m\le 100\) ),询问两点之间正好经过 \(k\) 条边的最短路( \(2\le k\le 1e6\) )。
题解
对于这种正好经过 \(k\) 条边的问题,使用矩阵快速幂求解。但是这里的矩阵快速幂需要进行修改,改为 \(C_{ij}=min(A_{ik}+B_{kj})\) 。因为 \(min\) 是满足结合律的,所以我们的这个新运算也是满足结合律的,所以我们可以进行矩阵快速幂。
代码如下:
#include<cstdio>
#include<iostream>
#include<cstring>
#include<queue>
#include<map>
#include<algorithm>
using namespace std;
const int N=1005,M=105;
int k,m,f,t;
int u[M],v[M],w[M];
int s[M*2],ls;
int mp[N];
struct Matrix
{
int n,m;
int h[M*2][M*2];
Matrix()
{
n=m=0;
memset(h,63,sizeof(h));
}
};
Matrix operator + (const Matrix a,const Matrix b)
{
Matrix ans;
ans.n=a.n;
ans.m=b.m;
for(int i=1;i<=a.n;++i)
{
for(int j=1;j<=b.m;++j)
{
for(int k=1;k<=a.m;++k)
ans.h[i][j]=min(ans.h[i][j],a.h[i][k]+b.h[k][j]);
}
}
return ans;
}
int main()
{
cin>>k>>m>>f>>t;
for(int i=1;i<=m;++i)
{
cin>>w[i]>>u[i]>>v[i];
s[++ls]=u[i];
s[++ls]=v[i];
}
sort(s+1,s+1+ls);
ls=unique(s+1,s+1+ls)-s-1;
for(int i=1;i<=ls;++i)
mp[s[i]]=i;
Matrix tmp,ans;
tmp.m=tmp.n=ls;
for(int i=1;i<=m;++i)
{
tmp.h[mp[u[i]]][mp[v[i]]]=w[i];
tmp.h[mp[v[i]]][mp[u[i]]]=w[i];
}
ans=tmp;
--k;
while(k>0)
{
if(k&1)
ans=ans+tmp;
tmp=tmp+tmp;
k>>=1;
}
printf("%d\n",ans.h[mp[f]][mp[t]]);
return 0;
}