fork download
  1. class ClosestPair
  2. end
  3. class << ClosestPair
  4. private
  5. def distance(p0,p1)
  6. a,b = p0[0]-p1[0], p0[1]-p1[1]
  7. dd = a*a+b*b
  8. Math.sqrt(dd)
  9. end
  10. def calc_index(d,p)
  11. [((2*p[0])/d).floor, ((2*p[1])/d).floor]
  12. end
  13. def calc_0(data)
  14. if data.length < 2
  15. raise "invalid input"
  16. end
  17. p0 = data[0]
  18. p1 = data[1]
  19. d = distance(p0,p1)
  20. pair = [0,1]
  21. h = {}
  22. h[calc_index(d,p0)] = 0
  23. h[calc_index(d,p1)] = 1
  24. cur = 2
  25. while cur < data.length
  26. idx = calc_index(d,data[cur])
  27. min = 2.0
  28. min_i = nil
  29. (-2..2).each do |y|
  30. (-2..2).each do |x|
  31. qi = h[[idx[0]+x, idx[1]+y]]
  32. next unless qi
  33. td = distance(data[cur],data[qi])
  34. if td < min
  35. min = td
  36. min_i = qi
  37. end
  38. end
  39. end
  40. if min_i && (min < d)
  41. pair = [cur, min_i]
  42. d = min
  43. h = {}
  44. (0..cur).each do |i|
  45. h[calc_index(d,data[i])] = i
  46. end
  47. else
  48. h[idx] = cur
  49. end
  50. cur += 1
  51. end
  52. pair
  53. end
  54. public
  55. def calc(data)
  56. calc_0(data.shuffle)
  57. end
  58. end
  59.  
  60. if __FILE__ == $0
  61. def time(mes, &blk)
  62. start_time = Time.now
  63. blk.call
  64. puts "%s : %.2f sec." % [mes, Time.now-start_time]
  65. end
  66. data = []
  67. n = 10000
  68. n.times do
  69. data << [Random.rand, Random.rand]
  70. end
  71. time "Randomized Closest Pair(#{n} items)" do
  72. ClosestPair::calc(data)
  73. end
  74. end
Success #stdin #stdout 0.56s 9112KB
stdin
Standard input is empty
stdout
Randomized Closest Pair(10000 items) : 0.53 sec.