/* * starSimQT_zeil.cpp * * Created on: Oct 20, 2013 * Author: Steven Zeil */ #include #include #include #include #include #include using namespace std; struct Point { int x, y, z; }; ostream& operator<< (ostream& out, const Point& p) { out << "(" << p.x << "," << p.y << "," << p.z << ")"; return out; } struct KDTreeNode { Point p; int level; KDTreeNode* below; KDTreeNode* above; KDTreeNode (const Point& pt, int levl); ~KDTreeNode(); int diff (const Point& pt) const; int rangeCount (const Point& pt, long K, long Ksq) const; long distSq (const Point& pt) const; }; KDTreeNode::KDTreeNode (const Point& pt, int levl) { p = pt; level = levl; below = above = 0; } KDTreeNode::~KDTreeNode() { delete below; delete above; } long KDTreeNode::distSq (const Point& pt)const { long dx = p.x - pt.x; long dy = p.y - pt.y; long dz = p.z - pt.z; return dx*dx + dy*dy + dz*dz; } int KDTreeNode::diff (const Point& pt) const { switch (level) { case 0: return pt.x - p.x; break; case 1: return pt.y - p.y; break; case 2: return pt.z - p.z; break; } return 0; } int KDTreeNode::rangeCount (const Point& pt, long K, long Ksq) const { int count = (distSq(pt) < Ksq) ? 1 : 0; int d = diff(pt); if (-d <= K && above != 0) count += above->rangeCount(pt, K, Ksq); if (d <= K && below != 0) count += below->rangeCount(pt, K, Ksq); return count; } KDTreeNode* insert (KDTreeNode* t, const Point& pt, int parentLevel) { if (t == 0) { t = new KDTreeNode (pt, (parentLevel+1) % 3); return t; } else { int d = t->diff(pt); if (d <= 0) { t->below = insert (t->below, pt, t->level); } else { t->above = insert (t->above, pt, t->level); } return t; } } class StarSimulation { KDTreeNode* root; Point* points; Point minima; Point maxima; int N; int K; long Ksq; int K_inner; public: StarSimulation (int n, int k, istream& in); ~StarSimulation(); long countPairs(); }; StarSimulation::StarSimulation(int n, int k, istream& in) : N(n), K(k) { Ksq = (long)K * (long)K; double innerSphere = 1.0 / sqrt(3.0); K_inner = (int)(innerSphere * (double)K); points = new Point[N]; root = 0; for (int i = 0; i < N; ++i) { in >> points[i].x >> points[i].y >> points[i].z; if (!in) { cerr << "error reading point " << i << " out of " << N << endl; exit(1); } } } StarSimulation::~StarSimulation() { delete [] points; delete root; } long StarSimulation::countPairs() { // Collect minima and maxima, and pandomly permute the points // so that we don't suffer for not having bothered with a // balanced tree algorithm. minima.x = maxima.x = points[0].x; minima.y = maxima.y = points[0].y; minima.z = maxima.z = points[0].z; for (int i = 1; i < N; ++i) { minima.x = min(minima.x, points[i].x); minima.y = min(minima.y, points[i].y); minima.z = min(minima.z, points[i].z); maxima.x = max(maxima.x, points[i].x); maxima.y = max(maxima.y, points[i].y); maxima.z = max(maxima.z, points[i].z); int k = rand() % (i + 1); swap (points[i], points[k]); } // Insert the points into the kD tree for (int i = 0; i < N; ++i) { root = insert(root, points[i], -1); } // Count the neighbors of each point long count = 0; for (int i = 0; i < N; ++i) { long c = root->rangeCount(points[i], K, Ksq); //cerr << "Count for " << points[i] << " is " << c << endl; count += c - 1; } return count; } void solve (istream& in) { int N, K; in >> N; while (N > 0) { in >> K; //cout << N << " " << M << endl; StarSimulation sim (N, K, in); long t = sim.countPairs(); cout << t/2L << endl; in >> N; } } int main (int argc, char** argv) { srand(23); if (argc > 1) { ifstream in (argv[1]); solve (in); } else solve(cin); return 0; }