zoukankan      html  css  js  c++  java
  • [USACO07NOV]牛继电器Cow Relays

    矩阵快速幂+倍增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与矩阵具有很好的相容性。

  • 相关阅读:
    Eclipse 导入项目乱码问题(中文乱码)
    sql中视图视图的作用
    Java基础-super关键字与this关键字
    Android LayoutInflater.inflate(int resource, ViewGroup root, boolean attachToRoot)的参数理解
    Android View和ViewGroup
    工厂方法模式(java 设计模式)
    设计模式(java) 单例模式 单例类
    eclipse乱码解决方法
    No resource found that matches the given name 'Theme.AppCompat.Light 的完美解决方案
    【转】使用 Eclipse 调试 Java 程序的 10 个技巧
  • 原文地址:https://www.cnblogs.com/bullshit/p/9689542.html
Copyright © 2011-2022 走看看