zoukankan      html  css  js  c++  java
  • 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;
    }
  • 相关阅读:
    Haskell Interactive Development in Emacs
    Access Java API in Groovy Script
    手工设置Eclipse文本编辑器的配色
    Color Theme of Emacs
    Gnucash的投资记录
    Special Forms and Syntax Sugars in Clojure
    Use w3m as Web Browser
    SSE指令集加速之 I420转BGR24
    【图像处理】 增加程序速度的方法
    TBB 入门笔记
  • 原文地址:https://www.cnblogs.com/WWHHTT/p/9898445.html
Copyright © 2011-2022 走看看