#include <cmath> #include <fstream> #include <iostream> #include <set> #include <stack> #include <vector> using namespace std; #define Dcout(x) cout << #x << ": " << (x) << endl struct Node { double x, y; int pts, cluster; bool visited= false; vector<int> contains; enum { Core= 0, Border= 1, Noise= 2 } tag; Node() : x(0), y(0), pts(1), cluster(0), tag(Noise) {} Node(double a, double b) : x(a), y(b), pts(1), cluster(-1), tag(Noise) {} Node(double a, double b, int c) : x(a), y(b), pts(1), cluster(c), tag(Noise) {} }; class DBSCAN { public: vector<set<int> *> cluster; vector<Node> a_node; vector<Node *> c_node; DBSCAN(double eps, int minpts, vector<struct Node> &l) : _eps(eps), _minpts(minpts) { _total= l.size(); a_node= l; dis= new double *[_total]; for (int i= 0; i < _total; ++i) { dis[i]= new double[_total]; } }
~DBSCAN() { delete[] dis; }
void FindCore(void) { for (int i= 0; i < _total; ++i) { for (int j= i + 1; j < _total; ++j) { dis[i][j]= EuclideanDis(a_node[i], a_node[j]); if (dis[i][j] <= _eps) { a_node[i].pts++; a_node[j].pts++; } } } for (int i= 0; i < _total; ++i) { if (a_node[i].pts >= _minpts) { a_node[i].tag= Node::Core; c_node.push_back(&a_node[i]); } } }
void ConnectCore(void) { for (int i= 0; i < c_node.size(); ++i) { for (int j= i + 1; j < c_node.size(); ++j) { if (EuclideanDis(*c_node[i], *c_node[j]) < _eps) { c_node[i]->contains.push_back(j); c_node[j]->contains.push_back(i); } } } } void DFSCore(void) { int cnt= -1; for (int i= 0; i < c_node.size(); i++) { stack<Node *> ps; if (c_node[i]->visited) continue; ++cnt; a_node[c_node[i]->cluster].cluster= cnt; ps.push(c_node[i]); Node *v; while (!ps.empty()) { v= ps.top(); v->visited= 1; ps.pop(); for (int j= 0; j < v->contains.size(); j++) { if (c_node[v->contains[j]]->visited) continue; c_node[v->contains[j]]->cluster= cnt; c_node[v->contains[j]]->visited= true; ps.push(c_node[v->contains[j]]); } } } } void AddBorder(void) { for (int i= 0; i < _total; ++i) { if (a_node[i].tag == Node::Core) { continue; } if (a_node[i].tag == Node::Noise) { a_node[i].cluster= -1; } for (int j= 0; j < c_node.size(); ++j) { if (EuclideanDis(a_node[i], *c_node[j]) < _eps) { a_node[i].tag= Node::Border; a_node[i].cluster= c_node[j]->cluster; break; } } } }
private: double _eps; int _total, _minpts; double **dis;
inline double EuclideanDis(const struct Node &a, const struct Node &b) { return sqrt(((a.x - b.x) * (a.x - b.x)) + ((a.y - b.y) * (a.y - b.y))); } };
int main(int argc, char const *argv[]) { vector<struct Node> nodes; ifstream fin("in"); if (!fin) { return -1; } else { int i= -1; char s[100]; for (double x, y; fin.getline(s, 100);) { sscanf(s, "%lf,%lf", &x, &y); nodes.push_back(Node(x, y, ++i)); } }
DBSCAN dbscan(0.1, 10, nodes); dbscan.FindCore(); dbscan.ConnectCore(); dbscan.DFSCore(); dbscan.AddBorder();
ofstream fout("out"); if (!fout) { return -1; } else { for (auto &it : dbscan.a_node) { fout << it.cluster << endl; } fout.close(); } return 0; }
|