1. 程式人生 > >POJ 3613 Cow Relays

POJ 3613 Cow Relays

長度 book 最短 floyd amp sca mat 定義 sort

  • 題目大意:給定起點和終點,求經過k條邊的最短路

  • 思路:倍增Floyd 矩陣快速冪優化

    其實,雖然被稱作倍增Floyd,但和Floyd關系好像並不大?

    按dp思想理解,設f(k,i,j)表示經過k條邊從ij的最小花費,則

    \(f(k,i,j)=min(f(k-1,i,p)+f(1,p,j))\)

    k次Floyd顯然會超時,現考慮定義新運算如下:

    對一張有n個點的圖,用n*n的鄰接矩陣來存儲,其中(i,j)表示從i到j的最短路長度

    A矩陣表示經過x條邊以後的最短路,B矩陣表示經過y條邊以後的最短路

    定義新運算:\(A*B=C\)

    \(C[i,j]=min_{k=1}^nA[i,k]+B[k,j]\)

    對這種矩陣運算,滿足結合律,可以用類似快速冪的倍增思想進行優化

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
const int maxn=210;//註意空間限制 數組開大直接報錯
int s,e,k,n,m,book[3005];
struct data {//離散化用
    int from,to,dis;
} node[3005];
struct Matrix {
    int mp[maxn][maxn];
    inline Matrix () {memset(mp,0x3f,sizeof(mp));}
    Matrix operator *(const Matrix &a)const {
        Matrix c;
        for(int k=1; k<=n; ++k) 
            for(int i=1; i<=n; ++i) 
                for(int j=1; j<=n; ++j)
                    c.mp[i][j]=min(c.mp[i][j],mp[i][k]+a.mp[k][j]);
        return c;
    }
} f,ans;
void ksm(){
    ans=f;
    while(k) {
        if(k&1) ans=ans*f;
        f=f*f;
        k>>=1;
    }
}
int main() {
    scanf("%d%d%d%d",&k,&m,&s,&e);
    for(int i=1,x,y,z; i<=m; ++i) {
        scanf("%d%d%d",&z,&x,&y);
        book[++n]=x;
        book[++n]=y;
        node[i].from=x;
        node[i].to=y;
        node[i].dis=z;
    }
    sort(book+1,book+1+n);
    int tot=unique(book+1,book+1+n)-(book+1);
    for(int i=1; i<=m; ++i) {
        node[i].from=lower_bound(book+1,book+1+tot,node[i].from)-book;
        node[i].to=lower_bound(book+1,book+1+tot,node[i].to)-book;
        f.mp[node[i].from][node[i].to]=f.mp[node[i].to][node[i].from]=node[i].dis;
    }
    s=lower_bound(book+1,book+1+tot,s)-book;
    e=lower_bound(book+1,book+1+tot,e)-book;
    n=tot;
    //以上為離散化內容
    --k;//經過k條邊 需要進行k-1次floyd
    ksm();
    printf("%d",ans.mp[s][e]);
    return 0;
}

POJ 3613 Cow Relays