• [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与矩阵具有很好的相容性。

  • 相关阅读:
    android so壳入口浅析
    PySide图形界面开发(一)
    对一个伪装成微信的加固病毒的分析
    ZjDroid工具介绍及脱壳详细示例
    用pyinstaller把python代码打包成exe可执行文件
    Android下so注入汇总
    利用drozer进行Android渗透测试
    OWASP移动安全漏洞Top 10
    python with原理
    腾讯云
  • 原文地址:https://www.cnblogs.com/bullshit/p/9689542.html
Copyright © 2020-2023  润新知