POJ 3613 Cow Relays

  • 题目大意:给定起点和终点,求经过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;
}
posted @ 2019-02-23 18:26  宇興  阅读(93)  评论(0编辑  收藏  举报