Guest User

Untitled

a guest
Dec 9th, 2016
54
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 6.46 KB | None | 0 0
  1. #include <algorithm>
  2. #include <vector>
  3. #include <climits>
  4. #include <unordered_map>
  5. #include <time.h>
  6. #include <random>
  7.  
  8. #define PAIR std::pair<double, double> // x y coordinates
  9. #define EPS 1e-8
  10. #define MARGIN 1e-3
  11.  
  12. // Eucledian distance
  13. double distance(PAIR p, PAIR q) {
  14. return sqrt((p.first - q.first) * (p.first - q.first) + (p.second - q.second) * (p.second - q.second));
  15. }
  16.  
  17. // brute force for small data set
  18. double closest_2d_points_slow(std::vector<PAIR> &a, int L, int R, std::vector<PAIR> &answer) {
  19. if (R - L < 1) return DBL_MAX;
  20.  
  21. answer.resize(2);
  22. answer[0] = a[L];
  23. answer[1] = a[L + 1];
  24. double d = distance(answer[0], answer[1]);
  25. for (int i = L; i < R; ++i)
  26. for (int j = i + 1; j <= R; ++j) {
  27. double dd = distance(a[i], a[j]);
  28. if (dd < d - EPS) {
  29. d = dd;
  30. answer[0] = a[i];
  31. answer[1] = a[j];
  32. }
  33. }
  34. return d;
  35. }
  36.  
  37. // estimate 'delta' by brute force on sqrt(n) points.
  38. double estimate_delta(std::vector<PAIR> &a) {
  39. int n = (int)a.size(), k = (int)sqrt(n), k1 = k;
  40. std::vector<PAIR> sample(k);
  41.  
  42. // choose k = sqrt(n) points randomly.
  43. std::mt19937 rng((unsigned int)time(0));
  44. for (int i = 0; i < n; ++i) {
  45. std::uniform_int_distribution<int> gen(0, n - i - 1);
  46. if (gen(rng) < k1) {
  47. sample[--k1] = a[i];
  48. }
  49. }
  50. return closest_2d_points_slow(sample, 0, k - 1, std::vector<PAIR>());
  51. }
  52.  
  53. // find x_min, x_max, y_min, y_max
  54. // answer[0] = x_min, answer[1] = x_max
  55. // answer[2] = y_min, answer[3] = y_max
  56. void minXY_maxXY(std::vector<PAIR> &a, double * answer) {
  57. answer[0] = answer[2] = DBL_MAX;
  58. answer[1] = answer[3] = DBL_MIN;
  59. int left = 0;
  60. if (a.size() % 2 > 0) { // odd number of points
  61. answer[0] = answer[1] = a[0].first;
  62. answer[2] = answer[3] = a[0].second;
  63. ++left;
  64. }
  65. for (int i = left; i < (int)a.size(); i += 2) {
  66. // x-coordinates
  67. if (a[i].first < a[i + 1].first - EPS) {
  68. if (answer[0] > a[i].first + EPS)
  69. answer[0] = a[i].first;
  70. if (answer[1] < a[i + 1].first - EPS)
  71. answer[1] = a[i + 1].first;
  72. }
  73. else {
  74. if (answer[0] > a[i + 1].first + EPS)
  75. answer[0] = a[i + 1].first;
  76. if (answer[1] < a[i].first - EPS)
  77. answer[1] = a[i].first;
  78. }
  79. // y-coordinates
  80. if (a[i].second < a[i + 1].second - EPS) {
  81. if (answer[2] > a[i].second + EPS)
  82. answer[2] = a[i].second;
  83. if (answer[3] < a[i + 1].second - EPS)
  84. answer[3] = a[i + 1].second;
  85. }
  86. else {
  87. if (answer[2] > a[i + 1].second + EPS)
  88. answer[2] = a[i + 1].second;
  89. if (answer[3] < a[i].second - EPS)
  90. answer[3] = a[i].second;
  91. }
  92. }
  93. answer[0] -= MARGIN;
  94. answer[1] += MARGIN;
  95. answer[2] -= MARGIN;
  96. answer[3] += MARGIN;
  97. }
  98.  
  99. // convert xy-coordinate to a number representing a cell in a rows x cols grid.
  100. int sub2ind(PAIR p, int rows, int cols, double x_min, double y_min, double delta) {
  101. return int(floor((p.second - y_min) / delta)) * cols + int(floor((p.first - x_min) / delta));
  102. }
  103.  
  104. // convert a cell number to (row, col)
  105. void ind2sub(int bin, int rows, int cols, int &row, int &col) {
  106. row = bin / cols;
  107. col = bin % cols;
  108. }
  109.  
  110. // return the neighbors of a cell
  111. void bin_neighbors(int bin, int rows, int cols, std::vector<int> &neighbors) {
  112. int row, col;
  113. ind2sub(bin, rows, cols, row, col);
  114. neighbors.clear();
  115. if (row == 0) {
  116. neighbors.push_back(bin + cols);
  117. if (col > 0)
  118. neighbors.push_back(bin + cols - 1);
  119. if (col < cols - 1) {
  120. neighbors.push_back(bin + 1);
  121. neighbors.push_back(bin + cols + 1);
  122. }
  123. return;
  124. }
  125. if (row == rows - 1) {
  126. if (col < cols - 1)
  127. neighbors.push_back(bin + 1);
  128. return;
  129. }
  130. neighbors.push_back(bin + cols);
  131. if (col > 0)
  132. neighbors.push_back(bin + cols - 1);
  133. if (col < cols - 1) {
  134. neighbors.push_back(bin + 1);
  135. neighbors.push_back(bin + cols + 1);
  136. }
  137. }
  138.  
  139. // Main function to compute the cloest 2d distance between 2 points using Rabin randomized algorithm.
  140. double closest_2d_points_rabin_randomized(std::vector<PAIR> &a, std::vector<PAIR> &answer) {
  141. if (a.size() < 25)
  142. return closest_2d_points_slow(a, 0, (int)a.size() - 1, answer);
  143.  
  144. // compute estimated delta and use it as a grid.
  145. answer.resize(2);
  146. double delta = estimate_delta(a);
  147. double mm[4];
  148. minXY_maxXY(a, mm);
  149.  
  150. // compute the number of rows and cols in a grid.
  151. int rows = (int)ceil((mm[3] - mm[2]) / delta);
  152. int cols = (int)ceil((mm[1] - mm[0]) / delta);
  153.  
  154. // project each point into cells according to its coordinate and delta.
  155. std::unordered_map<int, std::vector<PAIR>> point2bin;
  156. point2bin.reserve(a.size());
  157.  
  158. std::vector<int> bins;
  159. for (PAIR p : a) {
  160. int bin = sub2ind(p, rows, cols, mm[0], mm[2], delta);
  161. if (point2bin.find(bin) == point2bin.end()) {
  162. bins.push_back(bin);
  163. std::vector<PAIR> list(1, p);
  164. point2bin.insert(std::pair<int, std::vector<PAIR>>(bin, list));
  165. }
  166. else
  167. point2bin[bin].push_back(p);
  168. }
  169.  
  170. // look at each cell and its 4 adjacent cells.
  171. double d = DBL_MAX, dd = DBL_MAX;
  172. answer.resize(2);
  173. for (int bin : bins) {
  174. std::vector<PAIR> pts = point2bin[bin];
  175. int bin_size = (int)pts.size();
  176. std::vector<int> neighbors;
  177. bin_neighbors(bin, rows, cols, neighbors);
  178. for (int i = 0; i < bin_size; ++i) {
  179. // points in one cell
  180. for (int j = i + 1; j < bin_size; ++j) {
  181. dd = distance(pts[i], pts[j]);
  182. if (dd < d - EPS) {
  183. d = dd;
  184. answer[0] = pts[i];
  185. answer[1] = pts[j];
  186. }
  187. }
  188. // points in its 4 neighbors
  189. for (int another_bin : neighbors)
  190. if (point2bin.find(another_bin) != point2bin.end()) {
  191. for (PAIR q : point2bin[another_bin]) {
  192. dd = distance(pts[i], q);
  193. if (dd < d - EPS) {
  194. d = dd;
  195. answer[0] = pts[i];
  196. answer[1] = q;
  197. }
  198. }
  199. }
  200. }
  201. }
  202. return d;
  203. }
Add Comment
Please, Sign In to add comment