1. 程式人生 > 實用技巧 >題解 POJ3613 【Cow Relays】

題解 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;
}