P1613 跑路——倍增思想,floyd

https://www.luogu.org/problemnew/show/P1613

他有一个跑路机器,每次只能跑2k   (单位)路程,每相邻两个点的路程为1,也就是说如果连边1——》2——》3——》4——》5,路径长度为4,那么他可以一次从1跳到5;

n<=50;

我们要找的不是最短路径,而是一条路路程二进制数中1的个数最少;

这数据范围floyd已经够了,但是我们要提前处理一下连边;

我们将相距2 距离的两点距离设为1,这样再跑最短路就是正确答案;、

倍增思想体现在预处理上,;

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
typedef long long ll;
const int maxn=100;
int g[maxn][maxn][maxn],n,m;
ll dis[maxn][maxn];


void maker_road()
{
    for(int b=0;b<=64;b++)
    {
        for(int k=1;k<=n;k++)
        {
            for(int i=1;i<=n;i++)
            {
                for(int j=1;j<=n;j++)
                {
                    if(g[i][k][b-1]&&g[k][j][b-1])
                    {
                        g[i][j][b]=1;
                        dis[i][j]=1;
                    }
                }
            }
        }
    }
}

void floyd()
{
    for(int k=1;k<=n;k++)
    {
        for(int i=1;i<=n;i++)
        {
            for(int j=1;j<=n;j++)
            {
            //    if(dis[i][k]+dis[k][j]<dis[i][j])
                //{
                    dis[i][j]=min(dis[i][k]+dis[k][j],dis[i][j]);
                //}
            }
        }
    }
}
int main()
{
    memset(dis,0x3f,sizeof(dis));
    scanf("%d%d",&n,&m);
    for(int i=1;i<=m;i++)
    {
        int x,y;
        scanf("%d%d",&x,&y);
        g[x][y][0]=1;dis[x][y]=1;
    }
    maker_road();
    floyd();
    printf("%lld\n",dis[1][n]);
    return 0;
}

这里面的memset里面要开0x3f,开127会错出现负数,不知道为什么;

感谢 the_Death(https://www.luogu.org/space/show?uid=145411)的解答

{

 因为在弗洛伊德算法里面有dis[i][j]=min(dis[i][k]+dis[k][j],dis[i][j]);,

并且你无法保证所有的dis[][]的所有都会被更新为1的个数,

这就表示有些dis[][]中会以memset给的初值进行加法运算。

而由于memset的特性,你在赋初值的时候赋0x3f也就是127,它的加法会爆long long。

}

这个博客里面有memeset的用法技巧

 https://blog.csdn.net/Vmurder/article/details/46537613

posted @ 2019-09-26 17:03  AiRomance  阅读(185)  评论(0编辑  收藏  举报