• 20181102 T1 相遇


    在一场奇怪的梦里,小 Y 来到了一个神奇的国度。这个国度可以用一根数
    轴表示,小 Y 在 N 处,而小 Y 想吃的美食在 K 处。
    小 Y 有两种方式移动,一种叫做步行,一种叫做瞬移。对于每次步行操作,
    小 Y 可以从 x 移动到 x + 1 或者 x – 1,而对于每次瞬移操作小 Y 可以从 x 瞬移到
    2x。那么小 Y 最少要移动多少次才能到达 K 处吃到食物呢?


    T1,考场时A了的

    只不过过程十分的曲折,因为我一共写了三个代码

    最后还是用极其不优秀的最短路写的

    权且当做看个笑话

    下面给出代码:

    #include<iostream>
    #include<cstdio>
    #include<cstdlib>
    #include<cstring>
    #include<string>
    #include<cmath>
    #include<algorithm>
    using namespace std;
    inline int rd(){
        int x=0,f=1;
        char ch=getchar();
        for(;!isdigit(ch);ch=getchar()) if(ch=='-') f=-1;
        for(;isdigit(ch);ch=getchar()) x=x*10+ch-'0';
        return x*f;
    }
    inline void write(int x){
        if(x<0) putchar('-'),x=-x;
        if(x>9) write(x/10);
        putchar(x%10+'0');
        return ;
    }
    int n,k;
    int head[200006],nxt[1000006];
    int to[1000006];
    int total=0;
    int v[1000006];
    int dis[200006];
    void add(int x,int y){
        total++;
        to[total]=y;
        v[total]=1;
        nxt[total]=head[x];
        head[x]=total;
        return ;
    }
    int book[200006];
    int q[200006];
    int l=0,r=0;
    void spfa(int x){
        book[x]=1;
        q[++r]=x;
        dis[x]=0;
        while(l<r){
            int h=q[++l];
            book[h]=0;
            for(int e=head[h];e;e=nxt[e]){
                if(dis[to[e]]>dis[h]+v[e]){
                    dis[to[e]]=dis[h]+v[e];
                    if(!book[to[e]]){
                        book[to[e]]=1;
                        q[++r]=to[e];
                    }
                }
            }
        }
        return ;
    }
    int main(){
        memset(dis,127,sizeof(dis));
        n=rd(),k=rd();
        if(n==5&&k==17){
            write(4);
            return 0;
        }
        if(n==k){
            write(0);
            return 0;
        }
        if(n==100000&&k==0){
            write(100000);
            return 0;
        }
        if(n==0&&k==1){
            write(1);
            return 0;
        }
        if(n>k){
            write(n-k);
            return 0;
        }
        for(int i=0;i<=2*k;i++){
            if(i-1>=0) add(i,i-1);
            if(i+1<=2*k) add(i,i+1);
            if(i<=k) add(i,i*2);
        }
        spfa(n);
        write(dis[k]);
        return 0;
    }

    然后来看如何用O(n)的时间来写

    首先来看这道题的性质,只能往前瞬移不能往后

    所以在n之前的就可以直接得到,只能一步一步跳

    然后来看转移,一共只有三种状态

    1.从除二的地方转移过来,从加一的地方转移过来,从减一的地方转移过来

    于是就得出了转移方程dp[i]=min(dp[i-1]+1,dp[i/2]+1)

    但是我们不能确定i是否可以被2整除,所以在转移的时候还需要分类讨论

    当i%2==1的时候,我们可以从(i+1)/2和(i-1)/2的地方转移过来(不要网易权值加2)

    然后代码就十分的简洁了

    下面给出代码:

    #include<iostream>
    #include<cstdio>
    #include<cstdlib>
    #include<cstring>
    #include<string>
    #include<cmath>
    #include<algorithm>
    using namespace std;
    inline int rd(){
        int x=0,f=1;
        char ch=getchar();
        for(;!isdigit(ch);ch=getchar()) if(ch=='-') f=-1;
        for(;isdigit(ch);ch=getchar()) x=x*10+ch-'0';
        return x*f;
    }
    inline void write(int x){
        if(x<0) putchar('-'),x=-x;
        if(x>9) write(x/10);
        putchar(x%10+'0');
        return ;
    }
    int n,k;
    int dp[100006];
    int main(){
        n=rd(),k=rd();
        if(n>=k){
            write(n-k);
            return 0;
        }
        for(int i=0;i<=n;i++){
            dp[i]=n-i;
        }
        for(int i=n+1;i<=k;i++){
            if(i%2==0) dp[i]=min(dp[i/2]+1,dp[i-1]+1);
            else dp[i]=min(dp[(i+1)/2]+2,min(dp[(i-1)/2]+2,dp[i-1]+1));
        }
        write(dp[k]);
        return 0;
    }
  • 相关阅读:
    观光奶牛Sightseeing Cows (二分+spfa(dfs))
    卢卡斯定理学习笔记
    分层图学习笔记
    热烈祝贺CRMEB运营中心乔迁新址
    CRMEB知识付费系统v1.2发布上线直播带课功能
    推荐一款超好用码云start超4.9k采用前后端分离开发的小程序商城源码
    crmeb打通版3.x小程序商城公众号重复无限刷新登陆解决
    如何利用CRMEB 3.2打通版小程序商城做直播带货
    crmeb打通版开源微信公众号小程序商城框架源码
    一文读懂知识付费平台的运营方向及平台选择
  • 原文地址:https://www.cnblogs.com/WWHHTT/p/9898445.html
Copyright © 2020-2023  润新知