• 洛谷 P1613 跑路 解题报告


    P1613 跑路

    题目描述

    (A)的工作不仅繁琐,更有苛刻的规定,要求小(A)每天早上在(6:00)之前到达公司,否则这个月工资清零。可是小(A)偏偏又有赖床的坏毛病。于是为了保住自己的工资,小(A)买了一个十分牛B的空间跑路器,每秒钟可以跑(2^k)千米((k)是任意自然数)。当然,这个机器是用(long) (int)存的,所以总跑路长度不能超过(max) (long) (int)千米。小(A)的家到公司的路可以看做一个有向图,小(A)家为点(1),公司为点(n),每条边长度均为一千米。小(A)想每天能醒地尽量晚,所以让你帮他算算,他最少需要几秒才能到公司。数据保证(1)(n)至少有一条路径。

    输入输出格式

    输入格式:

    第一行两个整数(n),(m),表示点的个数和边的个数。

    接下来m行每行两个数字(u),(v),表示一条(u)(v)的边。

    输出格式:

    一行一个数字,表示到公司的最少秒数。

    说明

    (50)%的数据满足最优解路径长度(<=1000)

    (100)%的数据满足(n<=50)(m<=10000),最优解路径长度(<=) (max) (long) (int)


    首先,要确保自己的语文水平苟的住,这个鬼机器,每秒跑(2^kkm)的话是要跑刚好那么长的,不能多也不能少。

    那么岂不是代表,只有长为(2^kkm)的链才算是有效边吗?

    我们把所有有效边连上,跑最短路不就行了嘛。

    如何求有效边?

    (2^k?)有没有想到什么?

    (2^k=2^{k-1}+2^{k-1}?)

    对,就是倍增啊!

    (g[u][v][j])代表点(u)到点(v)存在或不存在长度为(2^j)的边。

    (g[u][k][j-1])(g[k][v][j-1])同时存在时,
    (g[u][v][j])存在。((k)是枚举的一维)


    #include <cstdio>
    #include <cstring>
    #include <queue>
    using namespace std;
    const int N=52;
    int g[N][N][70],n,m;
    //g[i][j][k]表示i点到j点存在边权为2^k的路
    int g0[N][N];
    int read()
    {
        int x=0;char c=getchar();
        while(c<'0'||c>'9') c=getchar();
        while(c>='0'&&c<='9') {x=x*10+c-'0';c=getchar();}
        return x;
    }
    queue <int > q;
    int used[N],dis[N];
    void spfa()
    {
        memset(used,0,sizeof(used));
        used[1]=1;
        memset(dis,0x3f,sizeof(dis));
        dis[1]=0;
        q.push(1);
        while(!q.empty())
        {
            int u=q.front();
            q.pop();
            used[u]=0;
            for(int v=1;v<=n;v++)
                if(g0[u][v]&&dis[v]>dis[u]+g0[u][v])
                {
                    dis[v]=dis[u]+g0[u][v];
                    if(!used[v])
                    {
                        used[v]=1;
                        q.push(v);
                    }
                }
        }
    }
    
    int main()
    {
        memset(g,0,sizeof(g));
        memset(g0,0,sizeof(g0));
        n=read(),m=read();
        int u,v;
        for(int i=1;i<=m;i++)
        {
            u=read(),v=read();
            g[u][v][0]=1;
            //f[u][v][0]=v;
        }
        for(int j=1;j<=64;j++)
            for(int k=1;k<=n;k++)
                for(u=1;u<=n;u++)
                    for(v=1;v<=n;v++)
                        if(g[u][k][j-1]&&g[k][v][j-1])
                            g[u][v][j]=1;
        for(u=1;u<=n;u++)
            for(v=1;v<=n;v++)
                for(int j=0;j<=64;j++)
                    if(g[u][v][j])
                    {
                        g0[u][v]=1;
                        break;
                    }
        spfa();
        printf("%d
    ",dis[n]);
        return 0;
    }
    
    

    2018.5.2

  • 相关阅读:
    [Leetcode]@python 65. Valid Number
    二维数组循环求出最大子数组
    一维循环的数组求出最大子数组的和
    电梯调度算法需求分析
    返回一个整数数组中最大子数组的和
    最大子数组求解
    小学数学计算题随机出题软件
    四则运算的设计思路
    学期读书计划
    软件工程概论第十一章
  • 原文地址:https://www.cnblogs.com/butterflydew/p/8999790.html
Copyright © 2020-2023  润新知