From 6f3a936cda8cb7ec03da98d078d5c34b430429f2 Mon Sep 17 00:00:00 2001 From: Haidong Ji Date: Mon, 17 Dec 2018 08:43:36 -0600 Subject: Closest Pair done in C++! Finally Divide and Conquer section is finished. A lot of work but so much fun! A few take aways: 1. Be careful when copying code over from Java to C++. Java does parameter passing through reference as default, but I forgot to add "&" in C++ code, which caused my code not passing earlier; 2. Avoid unnecessary calculation. For example, the sqrt calculation is not necessary, until the last step. Avoiding that in my Python code saved a lot of time. 3. It seems that preallocate vector size, if you know beforehand, is a good idea. Woohoo, onto the next section!--- PlaygroundCpp/.settings/language.settings.xml | 4 +- PlaygroundCpp/Sources/Playground.cpp | 218 +++++++++++++++++--------- 2 files changed, 148 insertions(+), 74 deletions(-) diff --git a/PlaygroundCpp/.settings/language.settings.xml b/PlaygroundCpp/.settings/language.settings.xml index aa6e0c9..1410d72 100644 --- a/PlaygroundCpp/.settings/language.settings.xml +++ b/PlaygroundCpp/.settings/language.settings.xml @@ -5,7 +5,7 @@ - + @@ -16,7 +16,7 @@ - + diff --git a/PlaygroundCpp/Sources/Playground.cpp b/PlaygroundCpp/Sources/Playground.cpp index dbb916c..d3330a1 100644 --- a/PlaygroundCpp/Sources/Playground.cpp +++ b/PlaygroundCpp/Sources/Playground.cpp @@ -1,97 +1,171 @@ -#include #include -#include #include +#include +#include +#include +#include //#include using std::vector; +using std::min; -struct Segment { - int start, end; - bool operator==(const Segment &s1) { - return (start == s1.start && end == s1.end); +struct Point { + int x, y; + bool operator==(const Point &p1) { + return (x == p1.x && y == p1.y); } }; -bool sortSeg(Segment i, Segment j) { - if (i.start == j.start) { - return i.end < j.end; +bool sortPointXDimension(Point i, Point j) { + if (i.x == j.x) { + return i.y < j.y; } - return i.start < j.start; + return i.x < j.x; } -vector fast_count_segments(vector starts, vector ends, - vector points) { - // Implement algo described here, really clever: - // https://www.coursera.org/learn/algorithmic-toolbox/discussions/all/threads/QJ1jK9wNEeWdPBL2iFTrAw/replies/Ihiw4txhEeWK5g7mfcS2Xw/comments/oyAMaeIiEeWyqwpvChh66Q - // l->1, p->2, r->3 for Segment.end property - vector s(starts.size() + ends.size() + points.size()); - vector p(points.size()); - Segment tempSeg; - for (int i = 0; i < p.size(); i++) { - tempSeg = {points[i], i}; - p[i] = tempSeg; - tempSeg = {points[i], 2}; - s[2 * starts.size() + i] = tempSeg; + +bool sortPointYDimension(Point i, Point j) { + if (i.y == j.y) { + return i.x < j.x; } - for (int i = 0; i < starts.size(); i++) { - tempSeg = {starts[i], 1}; - s[i] = tempSeg; - tempSeg = {ends[i], 3}; - s[i + starts.size()] = tempSeg; + return i.y < j.y; +} + +float distance(Point p1, Point p2) { + return pow(p1.x - p2.x, 2) + pow(p1.y - p2.y, 2); +} + +float baseCaseMinDistance(vector &ptsVector, int low, int high) { + if (high - low == 1) + return distance(ptsVector[low], ptsVector[high]); + if (high - low == 2) { + float f1 = distance(ptsVector[low], ptsVector[low + 1]); + float f2 = distance(ptsVector[low], ptsVector[high]); + float f3 = distance(ptsVector[high], ptsVector[low + 1]); + return min(f1, min(f2, f3)); } - std::sort(s.begin(), s.end(), sortSeg); - std::sort(p.begin(), p.end(), sortSeg); - vector results(points.size()); - int count = 0; - int j = 0; - for (int i = 0; i < s.size(); i++) { - if (s[i].end == 1) { - count = count + 1; - } - if (s[i].end == 2) { - results[j] = count; - j = j + 1; - } - if (s[i].end == 3) { - count = count - 1; + float f1 = distance(ptsVector[low], ptsVector[low + 1]); + float f2 = distance(ptsVector[low], ptsVector[low + 2]); + float f3 = distance(ptsVector[low], ptsVector[high]); + float f4 = distance(ptsVector[low + 1], ptsVector[low + 2]); + float f5 = distance(ptsVector[low + 1], ptsVector[high]); + float f6 = distance(ptsVector[low + 2], ptsVector[high]); + return min(f1, min(f2, min(f3, min(f4, min(f5, f6))))); +} + +float dPrimeDistance(vector &shadedPoints) { + float minDistance = FLT_MAX; + float tempDistance; + for (int i = 0; i < shadedPoints.size(); i++) { + for (int j = 1; j <= 5; j++) { + if (i + j < shadedPoints.size()) { + tempDistance = distance(shadedPoints[i], shadedPoints[i + j]); + minDistance = min(tempDistance, minDistance); + } } } - vector finalResults(points.size()); - for (int i = 0; i < finalResults.size(); i++) { - finalResults[p[i].end] = results[i]; + return minDistance; +} + +float minimalDistance(vector &ptsVector, int low, int high) { + if (high - low <= 3) { + return baseCaseMinDistance(ptsVector, low, high); + } + int mid = low + (high - low) / 2; + long midX = ptsVector[mid].x; + float f1 = minimalDistance(ptsVector, low, mid - 1); + float f2 = minimalDistance(ptsVector, mid, high); + float f = min(f1, f2); + vector shadedPoints; + for (int i = low; i <= high; i++) { + if (abs(ptsVector[i].x - midX) <= f) + shadedPoints.push_back(ptsVector[i]); } - return finalResults; + + std::sort(shadedPoints.begin(), shadedPoints.end(), sortPointYDimension); + + float fPrime = dPrimeDistance(shadedPoints); + + return min(f, fPrime); } +float minimalDistance(vector &x, vector &y) { + vector ptsVector(x.size()); + Point tempP; + + for (int i = 0; i < x.size(); i++) { + tempP = {x[i],y[i]}; + ptsVector[i] = tempP; + } -//TEST(SortSegment, Sort1) { -// vector starts = { 0, 7 }; -// vector ends = { 5, 10 }; -// vector points = { 1, 6, 11 }; -// vector results = { 1, 0, 0 }; + std::sort(ptsVector.begin(), ptsVector.end(), sortPointXDimension); + return sqrt(minimalDistance(ptsVector, 0, ptsVector.size() - 1)); +} +//TEST(SortPoint, Sort1) { +// vector x = { 4, -2, -3, -1, 2, -4, 1, -1, 3, -4, -2 }; +// vector y = { 4, -2, -4, 3, 3, 0, 1, -1, -1, 2, 4 }; +// vector p; +// Point tempP; +// +// for (int i = 0; i < x.size(); ++i) { +// tempP = {x[i],y[i]}; +// p.push_back(tempP); +// }; +// +// std::sort(p.begin(), p.end(), sortPointXDimension); +// +// ASSERT_EQ(p[0].x, -4); +// ASSERT_EQ(p[0].y, 0); +// +// std::sort(p.begin(), p.end(), sortPointYDimension); +// ASSERT_EQ(p[0].y, -4); +// ASSERT_EQ(p[0].x, -3); +// ASSERT_EQ(p[10].y, 4); +// ASSERT_EQ(p[10].x, 4); +//} +// +//TEST(PointDistance, Test1) { +// vector x = { 0, 0 }; +// vector y = { 3, 4 }; +// +// float f = minimalDistance(x, y); +// ASSERT_FLOAT_EQ(f, 5); +//} // -// vector cnt = fast_count_segments(starts, ends, points); +//TEST(ClosestDistance, Test1) { +// vector x = { 0, 3 }; +// vector y = { 0, 4 }; +// float result = 5.0; +// ASSERT_FLOAT_EQ(result, minimalDistance(x, y)); +//} // -// ASSERT_EQ(cnt[0], 1); -// ASSERT_EQ(cnt[1], 0); -// ASSERT_EQ(cnt[2], 0); -// ASSERT_EQ(cnt.size(), 3); +//TEST(ClosestDistance, Test2) { +// vector x = { 0, 3, 5 }; +// vector y = { 0, 4, 6 }; +// float result = 2.828427; +// ASSERT_FLOAT_EQ(result, minimalDistance(x, y)); +//} +// +//TEST(ClosestDistance, Test3) { +// vector x = { 7, 1, 4, 7 }; +// vector y = { 7, 100, 8, 7 }; +// float result = 0.0; +// ASSERT_FLOAT_EQ(result, minimalDistance(x, y)); +//} +// +//TEST(ClosestDistance, Test4) { +// vector x = { 4, -2, -3, -1, 2, -4, 1, -1, 3, -4, -2 }; +// vector y = { 4, -2, -4, 3, 3, 0, 1, -1, -1, 2, 4 }; +// float result = 1.4142135; +// ASSERT_FLOAT_EQ(result, minimalDistance(x, y)); //} int main() { - int n, m; - std::cin >> n >> m; - vector starts(n), ends(n); - for (size_t i = 0; i < starts.size(); i++) { - std::cin >> starts[i] >> ends[i]; - } - vector points(m); - for (size_t i = 0; i < points.size(); i++) { - std::cin >> points[i]; - } - //use fast_count_segments - vector cnt = fast_count_segments(starts, ends, points); - for (size_t i = 0; i < cnt.size(); i++) { - std::cout << cnt[i] << ' '; + size_t n; + std::cin >> n; + vector x(n); + vector y(n); + for (size_t i = 0; i < n; i++) { + std::cin >> x[i] >> y[i]; } + std::cout << std::fixed; + std::cout << std::setprecision(9) << minimalDistance(x, y) << "\n"; } - -- cgit v1.2.3