码迷,mamicode.com
首页 > 其他好文 > 详细

[USACO07NOV]牛继电器Cow Relays

时间:2018-09-22 12:48:16      阅读:174      评论:0      收藏:0      [点我收藏+]

标签:有一个   初始   out   ace   fast   lld   倍增   relay   cout   

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

[USACO07NOV]牛继电器Cow Relays

标签:有一个   初始   out   ace   fast   lld   倍增   relay   cout   

原文地址:https://www.cnblogs.com/bullshit/p/9689542.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!