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;
}
posted @ 2020-07-27 21:08  Point_King  阅读(59)  评论(0编辑  收藏  举报