Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- #include <iostream>
- #include <vector>
- #include <cmath>
- #include <stack>
- #include <set>
- #include <algorithm>
- using namespace std;
- const double MAX_COORDINATE = 1000000;
- // Структура, описывающая точку
- struct Point{
- double x; // Координата точки по x
- double y; // Координата точки по y
- double z; // Координата точки по z
- int num; // Номер точки
- Point(double X, double Y, double Z, int Number) : x(X), y(Y), z(Z), num(Number) {}
- };
- // Структура, описывающая плоскость
- struct Flat { // Ax + By + Cz + D = 0
- double A;
- double B;
- double C;
- double D;
- // Конструктор плоскости от значений чисел
- Flat(double a, double b, double c, double d) : A(a), B(b), C(c), D(d) {}
- // Констуктор плоскости от значений точек
- Flat(Point p, Point p0, Point tmp) {
- double a2 = p0.x - p.x; double b2 = p0.y - p.y; double c2 = p0.z - p.z;
- double a3 = tmp.x - p.x; double b3 = tmp.y - p.y; double c3 = tmp.z - p.z;
- A = b2*c3-c2*b3;
- B = c2*a3-a2*c3;
- C = a2*b3-b2*a3;
- D = -1*p.x*A -p.y*B - p.z*C;
- }
- };
- // Ребро задается двумя точками
- struct Edge {
- Point first; // Первая точка
- Point second; // Вторая
- Edge(Point F,Point S): first(F), second(S) {}
- };
- // Векторное умножение
- Point CrossProduct (const Point& A,const Point& B) {
- return Point{.x = A.z*B.y-A.y*B.z,
- .y = A.x*B.z-A.z*B.x,
- .z = A.y*B.x-A.x*B.y,
- .num = -1};
- }
- // Скалярное умножение
- double Scalar(const Point& A,const Point& B) {
- return(A.x*B.x+A.y*B.y+A.z*B.z);
- }
- // Треугольник задается тремя точками
- struct Triangle {
- Point first;
- Point second;
- Point third;
- vector<Edge> edges;
- void sort_dots(const Point& help){
- if(first.num < second.num && first.num < third.num) {
- Point u1(second.x - first.x,second.y - first.y,second.z - first.z,-1);
- Point u2(third.x - first.x,third.y - first.y,third.z - first.z,-1);
- Point u3(help.x - first.x,help.y - first.y,help.z - first.z,-1);
- if(Scalar(CrossProduct(u1,u2),u3) < 0) {
- Point T = second; second = third; third = T;
- }
- }
- else if(second.num < first.num && second.num < third.num) {
- Point T = second; second = first; first = T;
- Point u1(second.x - first.x,second.y - first.y,second.z - first.z,-1);
- Point u2(third.x - first.x,third.y - first.y,third.z - first.z,-1);
- Point u3(help.x - first.x,help.y - first.y,help.z - first.z,-1);
- if(Scalar(CrossProduct(u1,u2),u3) < 0) {
- T = second; second = third; third = T;
- }
- }
- else {
- Point T = third; third = first; first = T;
- Point u1(second.x - first.x,second.y - first.y,second.z - first.z,-1);
- Point u2(third.x - first.x,third.y - first.y,third.z - first.z,-1);
- Point u3(help.x - first.x,help.y - first.y,help.z- first.z,-1);
- if(Scalar(CrossProduct(u1,u2),u3) < 0) {
- T = second; second = third; third = T;
- }
- }
- }
- Triangle(Point F,Point S,Point T) : first(F), second(S), third(T) {
- edges.emplace_back(Edge(F,S));
- edges.emplace_back(Edge(S,T));
- edges.emplace_back(Edge(T,F));
- }
- };
- // Угол между плоскостями
- double get_angle(const Flat& First,const Flat& Second) {
- double numerator = abs(First.A*Second.A + First.B*Second.B + First.C*Second.C);
- double denominator = sqrt(First.A*First.A + First.B*First.B + First.C*First.C);
- denominator *= sqrt(Second.A*Second.A + Second.B*Second.B + Second.C*Second.C);
- return acos(numerator/denominator);
- }
- vector<Triangle> Find_Convex(const vector<Point>& dots) {
- size_t num_dots = dots.size(); // Общее количество точек
- set<set<int>> triplets_of_vertices; // Для запоминания тройки вершин - треугольника
- Point first_point(MAX_COORDINATE, MAX_COORDINATE, MAX_COORDINATE, -1); // Первая точка инициализации
- for (int i = 0; i < num_dots; i++) { // Находим эту самую точку first_point
- if (dots[i].z < first_point.z) {
- first_point = dots[i];
- } else if (dots[i].z == first_point.z) {
- if (dots[i].x < first_point.x) {
- first_point = dots[i];
- } else if (dots[i].x == first_point.x) {
- if (dots[i].y < first_point.y) {
- first_point = dots[i];
- }
- }
- }
- }
- Flat H(0, 0, 1, -1 * first_point.z); // z - first_point.z = 0 - уравнение плоскости перпендекулярной Oz и проходящий через first_point
- // В качестве l возьмем прямую проходящую через first_point и какую-то случайную точку
- Point l_point(rand() % 100 + 1985, rand() % 30 + 1985, rand() % 30 + 1985, -1);
- Point second_point(MAX_COORDINATE, MAX_COORDINATE, MAX_COORDINATE, -1); // Вторая точка первого треугольника
- double max_angle = M_PI;
- Flat G(-1, -1, -1, -1);
- for (int i = 0; i < num_dots; i++) { // Находим точку second_point, через которую пройдет H
- if (i != first_point.num) {
- Point tmp = dots[i];
- Flat tmp_G(first_point, l_point, tmp);
- double angle = get_angle(H, tmp_G);
- if (angle < max_angle) {
- second_point = tmp;
- max_angle = angle;
- G = tmp_G;
- }
- }
- }
- max_angle = M_PI;
- Point third_point(MAX_COORDINATE, MAX_COORDINATE, MAX_COORDINATE, -1);
- for (int i = 0; i < num_dots; i++) { // Находим последнюю точку third_point
- if (i != first_point.num && i != second_point.num) {
- Point tmp_dot = dots[i];
- Flat tmp_flat(first_point, second_point, tmp_dot);
- double angle = get_angle(G, tmp_flat);
- if (angle < max_angle) {
- third_point = tmp_dot;
- max_angle = angle;
- }
- }
- }
- vector<Triangle> ans;
- set<int> s_tmp = {first_point.num, second_point.num, third_point.num};
- triplets_of_vertices.insert(s_tmp);
- Triangle to_answer(first_point, second_point, third_point);
- if (first_point.num != 0 && second_point.num != 0 && third_point.num != 0) {
- to_answer.sort_dots(dots[0]);
- }
- else if (first_point.num != 1 && second_point.num != 1 && third_point.num != 1) {
- to_answer.sort_dots(dots[1]);
- }
- else if (first_point.num != 2 && second_point.num != 2 && third_point.num != 2) {
- to_answer.sort_dots(dots[2]);
- }
- else {
- to_answer.sort_dots(dots[3]);
- }
- ans.push_back(to_answer);
- stack<Triangle> triangles;
- triangles.push(to_answer);
- while(!triangles.empty()) {
- Triangle triangle_on_work = triangles.top(); triangles.pop();
- max_angle = M_PI;
- Edge e = triangle_on_work.edges[triangle_on_work.edges.size()-1]; triangle_on_work.edges.pop_back();
- Point the_new_point(MAX_COORDINATE, MAX_COORDINATE, MAX_COORDINATE, -1);
- for(int i = 0; i < num_dots; i++) {
- if(i != triangle_on_work.first.num && i != triangle_on_work.second.num && i != triangle_on_work.third.num){
- Point tmp_point = dots[i];
- Flat tmp_flat(e.first, e.second, tmp_point);
- double angle = get_angle(Flat(triangle_on_work.first, triangle_on_work.second, triangle_on_work.third), tmp_flat);
- if(angle < max_angle){
- the_new_point = tmp_point;
- max_angle = angle;
- }
- }
- }
- s_tmp.clear();
- s_tmp = {e.first.num,e.second.num,the_new_point.num};
- if(triplets_of_vertices.find(s_tmp) == triplets_of_vertices.end()) {
- triplets_of_vertices.insert(s_tmp);
- Triangle tmp_to_answer(e.first, e.second, the_new_point);
- if (e.first.num != 0 && e.second.num != 0 && the_new_point.num != 0) {
- tmp_to_answer.sort_dots(dots[0]);
- }
- else if (e.first.num != 1 && e.second.num != 1 && the_new_point.num != 1) {
- tmp_to_answer.sort_dots(dots[1]);
- }
- else if (e.first.num != 2 && e.second.num != 2 && the_new_point.num != 2) {
- tmp_to_answer.sort_dots(dots[2]);
- }
- else {
- tmp_to_answer.sort_dots(dots[3]);
- }
- ans.push_back(tmp_to_answer);
- triangles.push(tmp_to_answer);
- }
- if(!triangle_on_work.edges.empty()) {
- triangles.push(triangle_on_work);
- }
- }
- return ans;
- }
- bool compare_triangle(const Triangle& First,const Triangle& Second) {
- if(First.first.num < Second.first.num) {
- return true;
- }
- if(First.first.num > Second.first.num) {
- return false;
- }
- if(First.second.num < Second.second.num) {
- return true;
- }
- if(First.second.num > Second.second.num) {
- return false;
- }
- if(First.third.num <= Second.third.num) {
- return true;
- }
- return false;
- }
- int main() {
- int num_tests = 0; // Количество тестов
- cin >> num_tests;
- for(int test = 0; test < num_tests; test++) {
- int num_dots = 0; // Количество точек в тесте
- cin >> num_dots;
- vector<Point> dots; // Вектор точек в пространстве
- // Считываем все точки
- for(int i = 0; i < num_dots; i++) {
- double x = 0;
- double y = 0;
- double z = 0;
- cin >> x >> y >> z;
- Point tmp(x,y,z,i);
- dots.push_back(tmp);
- }
- vector<Triangle> convex = Find_Convex(dots); // Выпуклая оболочка
- std::sort(convex.begin(), convex.end(), compare_triangle);
- cout << convex.size() << "\n"; // Вывод данных
- for(auto i:convex) {
- cout << "3 " << i.first.num << " " << i.second.num << " " << i.third.num << "\n";
- }
- }
- return 0;
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement