POJ3613-Cow Relays(Floyd+矩阵乘法)

题目链接:POJ3613-Cow Relays

题意:

给一个无向图,求从s点出发,到t点刚好经过k条边的最短路。

题解:

首先考虑Floyd算法,平时我们是先枚举中转点,再枚举起点终点:

for(int k=1;k<=n;k++)
    for(int i=1;i<=n;i++)
        for(int j=1;j<=n;j++)

显然,这样能保证求出任意两点之间的最短路。考虑每个循环的含义,我们可以调换一下循环的顺序。

for(int i=1; i<=n; i++)
    for(int j=1; j<=n; j++)
        for(int k=1; k<=n; k++)

这样就是每次在任意两点之间加入一个点的最短路,显然作k-1次即可,用矩阵乘法维护。

参考代码:

#include<cstdio>
#include<cstring>
#include<map>
#include<algorithm>
#include<cmath>
using namespace std;
int k,n,m,s,t;
map<int,int>    mp;
struct MATRIX
{
    int mat[203][203];
    MATRIX operator * (MATRIX &MAT)
    {
        MATRIX temp;
        memset(temp.mat,0x3f,sizeof(temp.mat));
        for(int i=1; i<=n; i++)
            for(int j=1; j<=n; j++)
                for(int kk=1; kk<=n; kk++)
                    temp.mat[i][j]=min(temp.mat[i][j],MAT.mat[i][kk]+mat[kk][j]);
        return temp;
    }
} edge,ans;
void qpow()
{
    ans=edge;
    --k;
    while(k)
    {
        if(k%2)
            ans=ans*edge;
        edge=edge*edge;
        k/=2;
    }
}
int main()
{
    scanf("%d%d%d%d",&k,&m,&s,&t);
    mp.clear();
    memset(edge.mat,0x3f,sizeof(edge.mat));
    for(int i=1; i<=m; i++)
    {
        int u,v,w;
        scanf("%d%d%d",&w,&u,&v);
        if(mp[u])
            u=mp[u];
        else
            u=mp[u]=++n;
        if(mp[v])
            v=mp[v];
        else
            v=mp[v]=++n;
        edge.mat[u][v]=edge.mat[v][u]=w;
    }
    qpow();
    printf("%d\n",ans.mat[mp[s]][mp[t]]);
    return 0;
}

发表留言

人生在世,错别字在所难免,无需纠正。