计算最短网格距离

时间:2016-08-01 19:42:52

标签: java grid distance

  

考虑一个城市,街道完美布局,形成无限的方格。在这个城市中,发现两个给定点(原点和目的地)之间的最短路径比其他更复杂的城市要容易得多。作为一名新的优步开发人员,您的任务是创建一个执行此计算的算法。

     

考虑到用户的出发地和目的地坐标,他们每个都位于某条街道上,找到他们之间最短路线的长度,假设汽车只能沿着街道行驶。您可以保证至少有一个坐标是整数。

我正在努力找出这里的逻辑。有很多情况,我不知道如何容纳它们。这就是我到目前为止所拥有的

double perfectCity(double[] departure, double[] destination) {
    double yDist = Math.abs(destination[1]-departure[1]);
    double xDist = Math.abs(departure[1] - departure[0] + departure[1]-destination[0]);
    return xDist + yDist;
}

3 个答案:

答案 0 :(得分:3)

如果输入是整数,算法非常简单,只需找到x和y坐标之间的绝对值,然后将它们加在一起。这称为Manhattan distance

int distance = Math.abs(x1 - x2) + Math.abs(y1 - y2);

除了一种情况外,双打几乎完全相同。以下是一些可能性:

  1. 两个点都有整数坐标
  2. 一个点有整数坐标,另一个点只有一个整数坐标
  3. 两个点只有一个整数坐标,但它们位于不同的轴上。
  4. 两个点只有一个整数坐标,它们位于同一轴上。
  5. 可能性1-3使用与查找整数距离相同的算法都可以正常工作,除了#4有可能使轴在同一个块上。

    例如,如果输入为:{x: 0.5, y: 2}{x: 0.5, y: 3},则必须水平,垂直,然后再水平向后移动才能到达目的地。这与{x: 0.5, y: 2}{x: 1.5, y: 3}的输入不同,因为无需在同一轴上向后移动。

    因此,在之外的所有情况下都可以使用常规算法,以便在X和Y都具有浮点值且具有相同floor - ed值的情况下。

    您的代码看起来应该是这样的。

    import static java.lang.Math.*;
    
    public static double perfectCity(double x1, double y1, double x2, double y2) {
        double xDist = abs(x1 - x2);
        double yDist = abs(y1 - y2);
        if (floor(x1) != x1 && floor(x2) != x2 &&        // both Xs are doubles
            floor(x1) == floor(x2)) {                    // on the same block
            xDist = min(abs(x1 - floor(x1) + x2 - floor(x2)),
                        abs(x1 - ceil(x1)  + x2 - ceil(x2)));
        } else if (floor(y1) != y1 && floor(y2) != y2 && // both Ys are doubles
                   floor(y1) == floor(y2)) {             // on the same block
            yDist = min(abs(y1 - floor(y1) + y2 - floor(y2)),
                        abs(y1 - ceil(y1)  + y2 - ceil(y2)));
        }
        return xDist + yDist;
    }
    

    通过使用辅助函数分别计算每个轴,可以进一步简化这一过程。

    public static double perfectCity(double x1, double y1, double x2, double y2) {
        return travelOnAxis(x1, x2) + travelOnAxis(y1, y2);
    }
    
    private static double travelOnAxis(double from, double to) {
        if (Math.floor(from) == Math.floor(to)) {
            double dist = Math.abs((from % 1) + (to % 1));
            return Math.min(dist, 2 - dist);
        } else {
            return Math.abs(from - to);
        }
    }
    

答案 1 :(得分:1)

如果这是一个方格,你可以分别考虑x和y坐标;最小距离是两个方向上最小距离的总和。

p方向(xy),您必须从p1移至p2。从p1开始,您可以移至floor(p1)ceil(p1)以前往道路(如果p1是整数,则可能相等);从那里,您可以移至floor(p2)ceil(p2)所在的道路p2p2。从那里,您可以转到p

因此,min(abs(p1 - ceil(p1) ) + abs(ceil(p1) - floor(p2)) + abs(floor(p2) - p2), # (1) abs(p1 - floor(p1)) + abs(floor(p1) - ceil(p2) ) + abs(ceil(p2) - p2), # (2) abs(p1 - floor(p1)) + abs(floor(p1) - floor(p2)) + abs(floor(p2) - p2), # (3) abs(p1 - ceil(p1) ) + abs(ceil(p1) - ceil(p2) ) + abs(ceil(p2) - p2)) # (4) 方向的最小距离是

x

因此,您可以针对yfloor方向单独计算,然后添加。

为了说明这一点(分别缩写ceilf分别为pf(p1) p1 c(p1) +---O>>>>+>>>>>>>>+ . . +>>>O----+ f(p2) p2 c(p2) --------------------------------> p axis ):

>

这里用.表示最短路线。 p s在最短的路线上,但由于路线的那部分与p1 -> c(p1) -> f(p2) -> p2方向正交,因此它“朝向该方向的最小距离”“不计数”。

此处显示的最小路线p1,是上面的案例1.

可视化交换p2p1 ->f(p1) -> c(p2) -> p2应该不难,在这种情况下,最小路由是从pN == f(pN) == c(pN)开始(案例2)。

abs(pN - f(pN))的情况并无太大差异;那么,表达式abs(pN - c(pN))f(p1) == f(p2)的部分只是零。

略有不同的情况是f(p1) p1 c(p1) f(p1) p1 c(p1) +---O>>>>+ +<<<O----+ . . . . +-----O<<+ +>>>>>O--+ f(p2) p2 c(p2) f(p2) p2 c(p2) --------------------------------> p axis

p1 -> f(p1) -> f(p2) -> p2

在这种情况下,最小路线可以是p1 -> c(p1) -> c(p2) -> p2\(.*?\)(分别是案例3和4)。

答案 2 :(得分:0)

正如4castle所提到的,如果仅考虑整数输入,则问题很简单。在这种情况下,在“向前移动”之后你永远不必“向后移动”,因为你总能在一次移动中到达你的目的地。

但由于最多每个出发地/目的地需要考虑一个浮点​​数,我们需要考虑3个案例,(警告:冗长的解释) 。下面是一个带有解释的python2实现。

  1. 出发地和目的地的x坐标是相同的,并且不是浮点数。在这种情况下,最短距离只是y坐标之间的绝对差。相反的逻辑反之亦然。

    import math
    class Location():
        def __init__(self, cord):
            self.x = cord[0]
            self.y = cord[1]
    
    def perfectCity(departure, destination):
        l1 = Location(departure)
        l2 = Location(destination)
    
        if l1.x == l2.x and float(l1.x).is_integer() and float(l2.x).is_integer():
            return abs(l1.y-l2.y)
        if l1.y == l2.y and float(l1.y).is_integer() and float(l2.y).is_integer():
            return abs(l1.x-l2.x)
    
  2. 离开中的一个坐标是浮点时,则:

    • 如果x坐标是浮点,我们可以向后移动(向下舍入)或向前移动(向上舍入)。
    • 如果y坐标是浮点数,我们可以向下移动(向下舍入)或向上移动(向上舍入)。
    • 即使没有浮点坐标,上述逻辑也应该有效,因为我们在单位的任何一个方向上移动。
    • 一旦我们计算了这些,我们只选择下面的那些,
  3. return min(calc_round_up_dist(l1, l2), cal_round_down_dist(l1, l2))

    Lets take an example of (0.4, 1) and (0.9, 3)用于以下计算。

    1. 在计算round_up时,我们需要计算3个距离:

      • round_up_distance:浮点坐标的舍入值与原始浮点坐标之间的差值。如果没有浮点坐标,我们返回1 - 0.4 = 0.6 in the above example
      • non_floating_point差异:离开的非浮点坐标与目标的相应坐标之间的差异(请注意,这可能是浮点或不是浮点 abs(3-1) = 2 in the above example
      • 目的地坐标0.9 in the above case中离港的浮点对应点与四舍五入后的离境点浮点值的新值0.4 + 0.6(this is the round_up distance) = 1.0,即abs(0.9 - 1.0) = 0.1
      • 之间的差异
      • 添加以上所有3个,我们得到0.6 + 2 + .1 = 2.7这是最短的距离。
      • 需要进行相应的计算以进行四舍五入。我们在两者中选择最小值。 round_up和round_down的代码如下,

        import math
        class Location():
            def __init__(self, cord):
                self.x = cord[0]
                self.y = cord[1]
        
            def floating_point_round_up(self):
                if not float(self.x).is_integer():
                    return math.ceil(self.x) - self.x
                if not float(self.y).is_integer():
                    return math.ceil(self.y) - self.y
                return 0
        
            def floating_point_round_down(self):
                if not float(self.x).is_integer():
                    return self.x - math.floor(self.x)
                if not float(self.y).is_integer():
                    return self.y - math.floor(self.y)
                return 0
        
            def non_floating_point_diff(self, obj):
                if not float(self.x).is_integer():
                    return abs(self.y - obj.y)
                if not float(self.y).is_integer():
                    return abs(self.x - obj.x)
                return abs(self.y - obj.y)
        
            def floating_point_counterpart(self, obj):
                if not float(self.x).is_integer():
                    return obj.x
                if not float(self.y).is_integer():
                    return obj.y
                return obj.x
        
            def floating_point(self):
                if not float(self.x).is_integer():
                    return self.x
                if not float(self.y).is_integer():
                    return self.y
                return self.x
        
    2. 上下舍入功能如下,

      def calc_round_up_dist(l1, l2):
          dist = l1.floating_point_round_up()
          diff = l1.non_floating_point_diff(l2)
          floating_point_counterpart = l1.floating_point_counterpart(l2)
          new_val = dist + l1.floating_point()
          return dist + diff + abs(new_val - floating_point_counterpart)
      
      def cal_round_down_dist(l1, l2):
          dist = l1.floating_point_round_down()
          diff = l1.non_floating_point_diff(l2)
          floating_point_counterpart = l1.floating_point_counterpart(l2)
          new_val = l1.floating_point() - dist
          return dist + diff + abs(floating_point_counterpart - new_val)
      
    3. 最后调用上述方法的主函数

      def perfectCity(departure, destination):
          l1 = Location(departure)
          l2 = Location(destination)
      
          if l1.x == l2.x and float(l1.x).is_integer() and float(l2.x).is_integer():
              return abs(l1.y-l2.y)
          if l1.y == l2.y and float(l1.y).is_integer() and float(l2.y).is_integer():
              return abs(l1.x-l2.x)
      
          return min(calc_round_up_dist(l1, l2), cal_round_down_dist(l1, l2))