require 'set' Problem168 = Struct.new(:points) do def solve @distance_cache = [] @grid = Grid.new(points) w = isqrt(squared_distance_by_index(0, points.size - 1)) / 10 longest = ((w + 1) * 10) ** 2 shortest = -1 p 10 * (1..w + 1).bsearch {|d| len = d * 10 sqlen = len ** 2 next true if longest <= sqlen next false if sqlen < shortest if minmax = reach(len, sqlen) longest = minmax[1] if minmax[1] < longest shortest = minmax[0] if shortest < minmax[0] end !!minmax } end private def isqrt(x) (1..x).bsearch {|r| x <= r ** 2 } end def reach(len, sqlen) goal = points.size - 1 stack = [0] todo = Set.new(1..goal) longest = -1 shortest = 1 / 0.0 while i = stack.pop each_neighbor(i, len, sqlen, todo) do |j, distance| longest = distance if longest < distance shortest = distance if distance < shortest return shortest, longest if j.equal?(goal) stack << j end end nil end def each_neighbor(i, len, sqlen, todo) @grid.each_neighbor(i, len) do |j| next unless todo.include?(j) distance = squared_distance_by_index(i, j) if distance <= sqlen yield j, distance todo.delete j end end end def squared_distance_by_index(ia, ib) ia, ib = ib, ia if ib < ia @distance_cache[ia * points.size + ib] ||= squared_distance(points[ia], points[ib]) end def squared_distance(a, b) ax, ay = a bx, by = b (ax - bx) ** 2 + (ay - by) ** 2 end end class Grid def initialize(points) @n = 5 @ax, @ay, @bx, @by = aabb(points) @w = @bx - @ax @h = @by - @ay @cellw = @w / @n.to_r @cellh = @h / @n.to_r @points = points @bucket_of = points.map {|pt| which_bucket pt } @buckets = Array.new(@n * @n) { [] } @bucket_of.each_with_index {|b, i| @buckets[b] << i } end def aabb(points) ax = ay = bx = by = nil points.each do |x, y| ax = x if !ax || ax > x ay = y if !ay || ay > y bx = x if !bx || bx < x by = y if !by || by < y end return ax, ay, bx, by end def which_bucket(point) x, y = point [(y - @ay) * @n / @h, @n - 1].min * @n + [(x - @ax) * @n / @w, @n - 1].min end def each_neighbor(ipoint, radius) each_neighbor_bucket(ipoint, radius) do |bucket| @buckets[bucket].each {|i| yield i } end end def each_neighbor_bucket(ipoint, radius) bw = [(radius / @cellw).ceil, @n / 2].min bh = [(radius / @cellh).ceil, @n / 2].min b = @bucket_of[ipoint] bx = b % @n yield b (1..bw).each do |dx| yield b - dx if bx >= dx yield b + dx if bx + dx < @n end (1..bh).each do |dy| if (bpy = b - dy * @n) >= 0 yield bpy (1..bw).each do |dx| yield bpy - dx if bx >= dx yield bpy + dx if bx + dx < @n end end if (bpy = b + dy * @n) < @n * @n yield bpy (1..bw).each do |dx| yield bpy - dx if bx >= dx yield bpy + dx if bx + dx < @n end end end end end Problem168.new((1..gets.to_i).map{gets.split.map(&:to_i)}).solve