1. 程式人生 > >[USACO07NOV]牛繼電器Cow Relays

[USACO07NOV]牛繼電器Cow Relays

super turn con 倍增floyd tor 問題 實現 ace 答案

矩陣快速冪+倍增floyd

這道題十分神啊,floyd與矩陣快速冪(思想)結合。

矩陣快速冪的原理與普通快速冪一樣,因為矩陣乘法滿足交換律。

而這道題是讓我們求從s出發恰好經過k條邊(k<=1000000)到達t的最短路。如何考慮?圖有一個性質,我們令矩陣Ci j表示i j之間是否存在邊,那麽矩陣的k次冪就是任意點走過恰好k步能到達的點(值就是方案數)。利用這個思想,我們考慮floyd的實現,傳統的floyd是在一個矩陣中轉移,可以走任意步。我們改一改:

//floyd
    gk fina;
    for (int i=1;i<=tot;++i)
    for (int j=1;j<=tot;++j)
    fina.m[i][j]=INF;
    for (int k=1;k<=tot;++k)
    for (int i=1;i<=tot;++i) 
    for (int j=1;j<=tot;++j)
    {
        fina.m[i][j]=min(fina.m[i][j],a.m[i][k]+b.m[k][j]);
    }
    return fina;
//快速冪
    while (k)
    {
        if (k&1) e=floyd(e,firs);
        firs=floyd(firs,firs);
        k>>=1;
    }

firs就是一開始的圖,e初始值除了對角線以外其余都是INF。所以第一遍只能求出恰好一遍能走到的點,第二次就能求出恰好兩步的,下一次恰好4步。。。最終倍增地求出答案.
具體實現:用走 i 步的最短路和走 j 步的最短路生成一個答案:答案就是走 i*j 步的最短路

code:

#include<cstdio>
#include<cstring>
#include<iostream>
#include<queue>
#include<cstring>
#include<vector>
#include<stack>
#define int long long
#define SUPER_INT signed
const int maxn=106;
using namespace std;
const int INF=1e17;
struct gk
{
    int m[maxn][maxn];
};
int s,t,k,m,id[6000000],tot;
gk firs,ans;
inline gk floyad(gk a,gk b)
{
    gk fina;
    for (int i=1;i<=tot;++i)
    for (int j=1;j<=tot;++j)
    fina.m[i][j]=INF;
    for (int k=1;k<=tot;++k)
    for (int i=1;i<=tot;++i) 
    for (int j=1;j<=tot;++j)
    {
        fina.m[i][j]=min(fina.m[i][j],a.m[i][k]+b.m[k][j]);
    }
    return fina;
}    
gk e;
inline gk fast_pow(int k)
{

    for (int i=1;i<=tot;++i) e.m[i][i]=0;
    while (k)
    {
        if (k&1) e=floyad(e,firs);
        firs=floyad(firs,firs);
        k>>=1;
    }
    return e;
}
SUPER_INT main()
{
    for (int i=1;i<=105;++i)
    for (int j=1;j<=105;++j)
    firs.m[i][j]=ans.m[i][j]=e.m[i][j]=INF;
    cin>>k>>m>>s>>t;
    for (int i=1,x,y,c;i<=m;++i)
    {
        scanf("%lld%lld%lld",&c,&x,&y);
        if (!id[x]) id[x]=++tot;
        if (!id[y]) id[y]=++tot;
        firs.m[id[x]][id[y]]=firs.m[id[y]][id[x]]=c;
    }
    gk ans=fast_pow(k);
    cout<<ans.m[id[s]][id[t]];
    return 0;
}

收獲:

矩陣類問題註意打表考慮(手算太慢了,還要記住結論:矩陣的k次冪的性質,矩陣快速冪的實現,以及floyd與矩陣具有很好的相容性。

[USACO07NOV]牛繼電器Cow Relays