Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/jquery-ui/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Algorithm 火车站的最小站数_Algorithm_Dynamic Programming - Fatal编程技术网

Algorithm 火车站的最小站数

Algorithm 火车站的最小站数,algorithm,dynamic-programming,Algorithm,Dynamic Programming,我收到了这个面试问题,并陷入了困境: 从0号站开始,有无数个火车站 有无数列火车。第n列列车在k*2^(n-1)的所有站点停止,其中k在0和无穷大之间 当n=1时,第一列列车停在0、1、2、3、4、5、6等站点 当n=2时,第二列列车停在0、2、4、6、8等站点 当n=3时,第三列列车停在0、4、8、12等站点 给定起点站号和终点站号,返回它们之间的最小停车次数。你可以乘坐任何一列火车从一站到另一站 例如,start=1和end=4之间的最小停车次数是3,因为我们可以从1到2到4 我正在考虑一个

我收到了这个面试问题,并陷入了困境:

从0号站开始,有无数个火车站

有无数列火车。第n列列车在k*2^(n-1)的所有站点停止,其中k在0和无穷大之间

当n=1时,第一列列车停在0、1、2、3、4、5、6等站点

当n=2时,第二列列车停在0、2、4、6、8等站点

当n=3时,第三列列车停在0、4、8、12等站点

给定起点站号和终点站号,返回它们之间的最小停车次数。你可以乘坐任何一列火车从一站到另一站

例如,start=1和end=4之间的最小停车次数是3,因为我们可以从1到2到4

我正在考虑一个动态编程解决方案,它将存储在
dp[start][end]
start
end
之间的最小步骤数。我们将使用
start…mid1,mid1…mid2,mid2…mid3,…,midn…end来构建阵列。但我没能让它工作。你如何解决这个问题

澄清:

  • 列车只能从较低的停靠站前进到较高的停靠站
  • 火车可以在任何一个停站发车
  • 火车可以按任何顺序上车。可在登上n=3列车之前或之后登上n=1列车
  • 火车可以多次上车。例如,允许登上n=1列车,下一次登上n=2列车,最后再次登上n=1列车

  • 首先,问你是否可以倒转。听起来你不能,但正如这里所说的(这可能不能反映你收到的问题),这个问题从来没有为这些列车给出明确的方向。(我知道你现在已经编辑了你的问题,说你不能后退。)

    假设你不能倒退,策略很简单:总是乘坐编号最高的列车,但不会超过你的目的地

    假设您在stop
    s
    ,编号最高的列车停在您当前的位置,并且没有超调,是train
    k
    。在火车
    k
    上旅行一次会让你停下来
    s+2^(k-1)
    。没有更快的方法到达该站,也没有方法跳过该站-编号较低的列车不会跳过列车
    k
    的任何一个站,编号较高的列车也不会在列车
    k
    的站之间停车,所以在到达该站之前,您不能乘坐编号较高的列车。因此,训练
    k
    是您最好的即时行动


    考虑到这一战略,剩下的大部分优化是一种高效的比特旋转技巧,用于计算站点数量,而不明确计算路线上的每个站点。

    注意:我的答案下面当前评论的原因是,首先我写的这个算法完全错了,用户2357112让我从错误中清醒过来。所以我完全删除了这个算法,并根据user2357112对这个问题的回答编写了一个新的算法。我还在这个算法中添加了一些注释,以澄清每一行中发生了什么

    该算法从
    procedure main(Origin,Dest)
    开始,通过
    updateOrigin(Origin,Dest)

    主程序(起点、终点){
    //最后,我们得到了这个变量中的最小步数
    计数器=0;
    while(原点!=Dest){
    //我们用这个来模拟我们向目的地的移动
    原点=更新原点(原点,目标);
    计数器=计数器+1;
    }
    }
    过程更新原点(原点、目标){
    如果(原点==1)返回2;
    //我们必须找出哪列火车从我们的起点经过,从这个IF子句中得出的结果不是准确的选择,我们将来还需要做一些计算
    如果(原点==0){
    //所有列车都从0站通过,因此我们可以根据目的地选择列车
    n=对数2(目的地);
    }否则{
    //这是一个很好的起点来检查它是否从我们的原产地通过
    n=Log2(原点);
    }
    //现在让我们选择从起点经过且不超过终点的确切列车
    计数器=0;
    做{
    温度=计数器*2^(n-1);
    //我们找到了合适的火车
    如果(温度==原点){
    //我们搬到哪里去了
    返回原点+2^(n-1);
    //我们仍然不知道这列火车是否从我们的起点经过
    }elseif(温度<原点){
    计数器=计数器+1;
    //让我们再看看另一列火车
    }否则{
    n=n-1;
    计数器=0;
    }
    }while(温度<原点)
    }
    
    我认为这个问题根本不需要动态编程。它基本上可以用二进制计算来表示

    如果您将一个站点的编号转换为二进制,它会立即告诉您如何从站点0到达那里,例如

    6号站=110

    告诉您需要在一个车站分别乘坐n=3列车和n=2列车。因此,二进制表示的形式告诉您需要多少步骤

    下一步是弄清楚如何从一个车站到另一个车站。 我将通过示例再次说明这一点。假设你想从7号站到23号站

    站7=00111

    站23=10111

    你要做的第一件事是到达中间站。此停止由指定

    (起始站和结束站中相等的最高位)+(第一个不同位)+(用零填充)

    在我们的示例中,中间挡块为16(10000)。您需要执行的步骤可以通过该数字与起始站(7=00111)的差值来计算。在我们的示例中,这将产生

    10000-00111=1001

    现在你
    procedure main(Origin, Dest){
    
             //at the end we have number of minimum steps in this variable
             counter = 0;
    
             while(Origin != Dest){
    
                  //we simulate our movement toward destination with this
                  Origin = updateOrigin(Origin, Dest);
    
                  counter = counter + 1;
    
             }
    
    }
    
    procedure updateOrigin(Origin, Dest){
    
        if (Origin == 1) return 2;
    
        //we must find which train pass from our origin, what comes out from this IF clause is NOT exact choice and we still have to do some calculation in future
        if (Origin == 0){
    
           //all trains pass from stop 0, thus we can choose our train according to destination
           n = Log2(Dest);
    
        }else{
    
           //its a good starting point to check if it pass from our origin
           n = Log2(Origin);
    
        }
    
        //now lets choose exact train which pass from origin and doesn't overshoot destination
        counter = 0;
        do {
                 temp = counter * 2 ^ (n - 1);
    
                 //we have found suitable train
                 if (temp == Origin){
    
                     //where we have moved to
                     return Origin + 2 ^ ( n - 1 );
    
                 //we still don't know if this train pass from our origin
                 } elseif (temp < Origin){
    
                     counter = counter + 1;
    
                 //lets check another train
                 } else {
    
                     n = n - 1;
                     counter  = 0;
    
                 }
    
        }while(temp < origin)
    
    }
    
    000101 5        // Start
    000110 5+1=6
    001000 6+2=8
    010000 8+8=16
    100000 16+16=32 // 32+32 > 39, so start reversing the process
    100100 32+4=36  // Optimized with __builtin_popcount in code
    100110 36+2=38  // Optimized with __builtin_popcount in code
    100111 38+1=39  // Optimized with __builtin_popcount in code
    
    0010110100  2^2
    0010111000  2^3
    0011000000  2^6
    0100000000  2^7
    1000000000
    
    00101101  2^0
    00101110  2^1
    00110000  2^4
    01000000  2^6
    10000000
    
    00101101  2^0
     0010111  2^0
        0011  2^0
          01  2^0
           1
    
    1000000000 2^7
    1010000000 2^5
    1010100000 2^4
    1010110000 2^2
    1010110100
    
    public static int minimumNumberOfStops(int start, final int end) {
        // I would initialize it with 0 but the example given in the question states :
        // the minimum number of stops between start = 1 and end = 4 is 3 because we can get from 1 to 2 to 4
        int stops = 1;
        while (start < end) {
            start += findClosestPowerOfTwoLessOrEqualThan(end - start);
            stops++;
        }
        return stops;
    }
    
    private static int findClosestPowerOfTwoLessOrEqualThan(final int i) {
        if (i > 1) {
            return 2 << (30 - Integer.numberOfLeadingZeros(i));
        }
        return 1;
    }