BZOJ 1706. [usaco2007 Nov]relays 奶牛接力跑

传送门

边数不大,可以把点离散化,然后点数就只有 $200$

考虑 $dp$,设 $f[k][i][j]$ 表示走了 $k$ 步,从 $i$ 到 $j$ 的最小路程,发现转移可以倍增优化

$f[k][i][j]=min(f[k/2][i][j],f[k/2][i][l]+f[k/2][l][j])$

然后把 $f$ 滚动一下,做成矩阵,像矩阵快速幂一样搞就好了

这种方法好像有个名字叫倍增优化的 $floyd$?不太懂和 $floyd$ 有啥关系

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
using namespace std;
typedef long long ll;
inline int read()
{
    int x=0,f=1; char ch=getchar();
    while(ch<'0'||ch>'9') { if(ch=='-') f=-1; ch=getchar(); }
    while(ch>='0'&&ch<='9') { x=(x<<1)+(x<<3)+(ch^48); ch=getchar(); }
    return x*f;
}
const int N=207;
int n,m,S,T,cnt;
struct Matrix {
    int a[N][N];
    Matrix () { memset(a,0x3f,sizeof(a)); }
    inline Matrix operator * (const Matrix &tmp) const {
        Matrix res;
        for(int i=1;i<=cnt;i++)
            for(int j=1;j<=cnt;j++)
                for(int k=1;k<=cnt;k++)
                    res.a[i][j]=min(res.a[i][j],a[i][k]+tmp.a[k][j]);
        return res;
    }
}mp;
Matrix ksm(Matrix x,int y)
{
    Matrix res; for(int i=1;i<=cnt;i++) res.a[i][i]=0;
    while(y)
    {
        if(y&1) res=res*x;
        x=x*x; y>>=1;
    }
    return res;
}
int d[N],u[N],v[N],l[N];
int main()
{
    n=read(),m=read(),S=read(),T=read();
    for(int i=1;i<=m;i++)
    {
        l[i]=read(),u[i]=read(),v[i]=read();
        d[++cnt]=u[i],d[++cnt]=v[i];
    }
    sort(d+1,d+cnt+1); cnt=unique(d+1,d+cnt+1)-d-1;
    for(int i=1;i<=m;i++)
    {
        int x=lower_bound(d+1,d+cnt+1,u[i])-d,y=lower_bound(d+1,d+cnt+1,v[i])-d;
        mp.a[x][y]=mp.a[y][x]=l[i];
    }
    mp=ksm(mp,n); S=lower_bound(d+1,d+cnt+1,S)-d; T=lower_bound(d+1,d+cnt+1,T)-d;
    printf("%d\n",mp.a[S][T]);
    return 0;
}

 

posted @ 2019-08-26 10:12  LLTYYC  阅读(160)  评论(0编辑  收藏  举报