[POJ3613] Cow Relays(Floyd+矩阵快速幂)

解题报告

感觉这道题gyz大佬以前好像讲过一道差不多的?然鹅我这个蒟蒻发现矩阵快速幂已经全被我还给老师了...又恶补了一遍,真是恶臭啊。

题意

给定一个T(2 <= T <= 100)条边的无向图,求SE恰好经过N(2 <= N <= 1000000)条边的最短路。

Idea

用Floyd和矩阵快速幂优化的产物。具体等咱下了课再好好说...

用一个矩阵a(i, j)来表示i到j经过若干条边的最短路,初始化a为i到j边的长度,没有则是正无穷。

然后重载*运算符,比如a矩阵表示经过n条边,b矩阵表示经过m条边,那么a * b得到的矩阵表示经过m + n条边,采用Floyd的思想进行更新。

为了省时间,用了快速幂,这样时间复杂度达到了O(n^3logk),可以通过。

#include<cstdio>
#include<iostream>
#include<map>
#include<algorithm>
#include<cstring>
#define ll long long
#define Dio ios::sync_with_stdio(0);
using namespace std;
const int maxn=200+1;
ll n,m,x,y,z,K;
map<int ,int> mapp;//数据中最多有100条边,说明最多有200个点,然鹅点的编号可达1000,所以离散化一下
struct Matrix{//矩阵的类
    int a[maxn][maxn];
    Matrix operator *(const Matrix& r){//按floyd重载矩阵乘法
        Matrix c;
        memset(c.a,0x3f,sizeof(c.a));
        for(int k=1;k<=n;k++)//floyd模板
        for(int i=1;i<=n;i++)
        for(int j=1;j<=n;j++){
            c.a[i][j]=min(c.a[i][j],a[i][k]+r.a[k][j]);
        }
        return c;
    }
}st,ans;
void Pow(){//快速幂模板
    ans=st;
    K--;
    while(K){
        if(K&1)  ans=ans*st;
        st=st*st;
        K>>=1;
    }
}
int main(){
    Dio
    ll s,t;
    cin>>K>>m>>s>>t;
    memset(st.a,0x3f,sizeof(st.a));
    for(int i=1;i<=m;i++){
        int x,y,z;
        cin>>z>>x>>y;
        if(mapp[x]) x=mapp[x];
        else x=mapp[x]=++n;
        if(mapp[y]) y=mapp[y];
        else y=mapp[y]=++n;
        st.a[x][y]=st.a[y][x]=z;
    }
    Pow();
    cout<<ans.a[mapp[s]][mapp[t]]<<endl;
    return 0;
}
原文地址:https://www.cnblogs.com/Zfio/p/12793843.html