zoukankan      html  css  js  c++  java
  • bzoj2165: 大楼(倍增floyd)

      题目大意:一个有向图,n(<=100)个点求一条长度>=m(<=10^18)的路径最少经过几条边。

      一开始以为是矩乘,蓝鹅当时还没开始写,所以好像给CYC安利错了嘿嘿嘿QWQ

      第一眼看到这题就想到了某题(戳我),最后只想出一半。。。

      倍增floyd:f[p][i][j]表示走了2^p条边,从i到j的最长路径,然后则有:f[p][i][j]=max(f[p][i][j],f[p-1][i][k]+f[p-1][k][j]);

      当跑倍增floyd的时候,1到某个点路径长度>=m则记录p后break。但是这个p只能告诉你答案在2^(p-1)~2^p之间,那到底怎么统计最少经过几条边儿呢?这就是我当时没想出来的>_<。。。

      看了题解,ciao,sb了QAQ。。。把这个p按高位到低位贪心,新增一个g[i][j]数组表示当前i到j的最长路径,如果1到某个点长度>=m就不记录,否则每次用f[p][i][k]+g[k][j]来更新g数组,并给ans+=1<<p,这样就可以统计出路径<m的答案了,这个时候随便走一步就>=m,所以输出ans+1就行辣!

      初始化-233333333不够小害我WA了好几次QAQ【于是我就改成了-2333333333333333333嘿嘿嘿

      然后还学会了新姿势!

    try
    {
        throw(true);
    }catch(bool){}
    View Code

    代码如下:

    #include<iostream>
    #include<cstring>
    #include<cstdlib>
    #include<cstdio>
    #define ll long long
    using namespace std;
    int n,p,T;
    ll f[61][110][110],h[110][110],g[110][110],ans,m,x;
    int main()
    {
        scanf("%d",&T);
        while(T--)
        {
            ans=0;
            scanf("%d%lld",&n,&m);
            memset(f,0xef,sizeof(f));
            memset(g,0xef,sizeof(g));  
            for(int i=1;i<=n;i++)g[i][i]=0;  
            for(int i=1;i<=n;i++)
            for(int j=1;j<=n;j++)
            scanf("%lld",&x),f[0][i][j]=x?x:-2333333333333333333;  
            try
            {
                for(p=1;p<=61;p++)
                for(int k=1;k<=n;k++)
                for(int i=1;i<=n;i++)
                for(int j=1;j<=n;j++)
                {
                    f[p][i][j]=max(f[p][i][j],f[p-1][i][k]+f[p-1][k][j]);
                    if(i==1&&f[p][i][j]>=m)throw(true);
                }
            }catch(bool){}
            while(p--)
            {
                for(int i=1;i<=n;i++)for(int j=1;j<=n;j++)if(i==j)h[i][j]=0;else h[i][j]=-233333333;
                try
                {
                    for(int k=1;k<=n;k++)
                    for(int i=1;i<=n;i++)
                    for(int j=1;j<=n;j++)
                    {
                        h[i][j]=max(h[i][j],f[p][i][k]+g[k][j]);
                        if(i==1&&h[i][j]>=m)throw(true);
                    }
                    memcpy(g,h,sizeof(g));
                    ans+=1ll<<p;
                }catch(bool){}
            }
            printf("%lld
    ",ans+1);
        }
    }
    View Code
  • 相关阅读:
    using 关键字在 C++ 中的几种用法
    Chromium 修改图片资源
    SAM&广义SAM
    Burnside和Polya
    笔记:杜教筛
    笔记:莫比乌斯反演
    Miller-Rabin
    点分治
    虚树
    计算几何
  • 原文地址:https://www.cnblogs.com/Sakits/p/6535820.html
Copyright © 2011-2022 走看看