Advertisement
faunuss

Untitled

Nov 24th, 2017
91
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 10.73 KB | None | 0 0
  1. #include <iostream>
  2. #include <vector>
  3. #include <cmath>
  4. #include <stack>
  5. #include <set>
  6. #include <algorithm>
  7. using namespace std;
  8.  
  9. const double MAX_COORDINATE = 1000000;
  10.  
  11. // Структура, описывающая точку
  12. struct Point{
  13.     double x;   // Координата точки по x
  14.     double y;   // Координата точки по y
  15.     double z;   // Координата точки по z
  16.     int num;    // Номер точки
  17.  
  18.     Point(double X, double Y, double Z, int Number) : x(X), y(Y), z(Z), num(Number) {}
  19. };
  20.  
  21. // Структура, описывающая плоскость
  22. struct Flat { // Ax + By + Cz + D = 0
  23.     double A;
  24.     double B;
  25.     double C;
  26.     double D;
  27.  
  28.     // Конструктор плоскости от значений чисел
  29.     Flat(double a, double b, double c, double d) : A(a), B(b), C(c), D(d) {}
  30.  
  31.     // Констуктор плоскости от значений точек
  32.     Flat(Point p, Point p0, Point tmp) {
  33.         double a2 = p0.x - p.x; double b2 = p0.y - p.y; double c2 = p0.z - p.z;
  34.         double a3 = tmp.x - p.x; double b3 = tmp.y - p.y; double c3 = tmp.z - p.z;
  35.  
  36.         A = b2*c3-c2*b3;
  37.         B = c2*a3-a2*c3;
  38.         C = a2*b3-b2*a3;
  39.         D = -1*p.x*A -p.y*B - p.z*C;
  40.     }
  41. };
  42.  
  43. // Ребро задается двумя точками
  44. struct Edge {
  45.     Point first; // Первая точка
  46.     Point second;   // Вторая
  47.  
  48.     Edge(Point F,Point S): first(F), second(S) {}
  49. };
  50.  
  51. // Векторное умножение
  52. Point CrossProduct (const Point& A,const Point& B) {
  53.     return Point{.x = A.z*B.y-A.y*B.z,
  54.                  .y = A.x*B.z-A.z*B.x,
  55.                  .z = A.y*B.x-A.x*B.y,
  56.                  .num = -1};
  57. }
  58.  
  59. // Скалярное умножение
  60. double Scalar(const Point& A,const Point& B) {
  61.     return(A.x*B.x+A.y*B.y+A.z*B.z);
  62. }
  63.  
  64. // Треугольник задается тремя точками
  65. struct Triangle {
  66.     Point first;
  67.     Point second;
  68.     Point third;
  69.     vector<Edge> edges;
  70.  
  71.     void sort_dots(const Point& help){
  72.         if(first.num < second.num && first.num < third.num) {
  73.             Point u1(second.x - first.x,second.y - first.y,second.z - first.z,-1);
  74.             Point u2(third.x - first.x,third.y - first.y,third.z - first.z,-1);
  75.             Point u3(help.x - first.x,help.y - first.y,help.z - first.z,-1);
  76.  
  77.             if(Scalar(CrossProduct(u1,u2),u3) < 0) {
  78.                 Point T = second; second = third; third = T;
  79.             }
  80.         }
  81.         else if(second.num < first.num && second.num < third.num) {
  82.             Point T = second; second = first; first = T;
  83.  
  84.             Point u1(second.x - first.x,second.y - first.y,second.z - first.z,-1);
  85.             Point u2(third.x - first.x,third.y - first.y,third.z - first.z,-1);
  86.             Point u3(help.x - first.x,help.y - first.y,help.z - first.z,-1);
  87.  
  88.             if(Scalar(CrossProduct(u1,u2),u3) < 0) {
  89.                 T = second; second = third; third = T;
  90.             }
  91.         }
  92.         else {
  93.             Point T = third; third = first; first = T;
  94.             Point u1(second.x - first.x,second.y - first.y,second.z - first.z,-1);
  95.             Point u2(third.x - first.x,third.y - first.y,third.z - first.z,-1);
  96.             Point u3(help.x - first.x,help.y - first.y,help.z- first.z,-1);
  97.  
  98.             if(Scalar(CrossProduct(u1,u2),u3) < 0) {
  99.                 T = second; second = third; third = T;
  100.             }
  101.         }
  102.     }
  103.  
  104.     Triangle(Point F,Point S,Point T) : first(F), second(S), third(T) {
  105.         edges.emplace_back(Edge(F,S));
  106.         edges.emplace_back(Edge(S,T));
  107.         edges.emplace_back(Edge(T,F));
  108.     }
  109. };
  110.  
  111. // Угол между плоскостями
  112. double get_angle(const Flat& First,const Flat& Second) {
  113.     double numerator = abs(First.A*Second.A + First.B*Second.B + First.C*Second.C);
  114.     double denominator = sqrt(First.A*First.A + First.B*First.B + First.C*First.C);
  115.     denominator *= sqrt(Second.A*Second.A + Second.B*Second.B + Second.C*Second.C);
  116.     return acos(numerator/denominator);
  117. }
  118.  
  119. vector<Triangle> Find_Convex(const vector<Point>& dots) {
  120.     size_t num_dots = dots.size();  // Общее количество точек
  121.     set<set<int>> triplets_of_vertices; // Для запоминания тройки вершин - треугольника
  122.  
  123.     Point first_point(MAX_COORDINATE, MAX_COORDINATE, MAX_COORDINATE, -1); // Первая точка инициализации
  124.  
  125.     for (int i = 0; i < num_dots; i++) {  // Находим эту самую точку first_point
  126.         if (dots[i].z < first_point.z) {
  127.             first_point = dots[i];
  128.         } else if (dots[i].z == first_point.z) {
  129.             if (dots[i].x < first_point.x) {
  130.                 first_point = dots[i];
  131.             } else if (dots[i].x == first_point.x) {
  132.                 if (dots[i].y < first_point.y) {
  133.                     first_point = dots[i];
  134.                 }
  135.             }
  136.         }
  137.     }
  138.  
  139.     Flat H(0, 0, 1, -1 * first_point.z); // z - first_point.z = 0 - уравнение плоскости перпендекулярной Oz и проходящий через first_point
  140.  
  141.     // В качестве l возьмем  прямую проходящую через first_point и какую-то случайную точку
  142.     Point l_point(rand() % 100 + 1985, rand() % 30 + 1985, rand() % 30 + 1985, -1);
  143.  
  144.     Point second_point(MAX_COORDINATE, MAX_COORDINATE, MAX_COORDINATE, -1); // Вторая точка первого треугольника
  145.     double max_angle = M_PI;
  146.  
  147.     Flat G(-1, -1, -1, -1);
  148.     for (int i = 0; i < num_dots; i++) {  // Находим точку second_point, через которую пройдет H
  149.         if (i != first_point.num) {
  150.             Point tmp = dots[i];
  151.             Flat tmp_G(first_point, l_point, tmp);
  152.             double angle = get_angle(H, tmp_G);
  153.             if (angle < max_angle) {
  154.                 second_point = tmp;
  155.                 max_angle = angle;
  156.                 G = tmp_G;
  157.             }
  158.         }
  159.     }
  160.    
  161.     max_angle = M_PI;
  162.     Point third_point(MAX_COORDINATE, MAX_COORDINATE, MAX_COORDINATE, -1);
  163.     for (int i = 0; i < num_dots; i++) { // Находим последнюю точку third_point
  164.         if (i != first_point.num && i != second_point.num) {
  165.             Point tmp_dot = dots[i];
  166.             Flat tmp_flat(first_point, second_point, tmp_dot);
  167.             double angle = get_angle(G, tmp_flat);
  168.             if (angle < max_angle) {
  169.                 third_point = tmp_dot;
  170.                 max_angle = angle;
  171.             }
  172.         }
  173.     }
  174.     vector<Triangle> ans;
  175.     set<int> s_tmp = {first_point.num, second_point.num, third_point.num};
  176.     triplets_of_vertices.insert(s_tmp);
  177.  
  178.     Triangle to_answer(first_point, second_point, third_point);
  179.     if (first_point.num != 0 && second_point.num != 0 && third_point.num != 0) {
  180.         to_answer.sort_dots(dots[0]);
  181.     }
  182.     else if (first_point.num != 1 && second_point.num != 1 && third_point.num != 1) {
  183.         to_answer.sort_dots(dots[1]);
  184.     }
  185.     else if (first_point.num != 2 && second_point.num != 2 && third_point.num != 2) {
  186.         to_answer.sort_dots(dots[2]);
  187.     }
  188.     else {
  189.         to_answer.sort_dots(dots[3]);
  190.     }
  191.     ans.push_back(to_answer);
  192.  
  193.     stack<Triangle> triangles;
  194.     triangles.push(to_answer);
  195.  
  196.     while(!triangles.empty()) {
  197.         Triangle triangle_on_work = triangles.top(); triangles.pop();
  198.         max_angle = M_PI;
  199.         Edge e = triangle_on_work.edges[triangle_on_work.edges.size()-1]; triangle_on_work.edges.pop_back();
  200.  
  201.         Point the_new_point(MAX_COORDINATE, MAX_COORDINATE, MAX_COORDINATE, -1);
  202.         for(int i = 0; i < num_dots; i++) {
  203.             if(i != triangle_on_work.first.num && i != triangle_on_work.second.num && i != triangle_on_work.third.num){
  204.                 Point tmp_point = dots[i];
  205.                 Flat tmp_flat(e.first, e.second, tmp_point);
  206.                 double angle = get_angle(Flat(triangle_on_work.first, triangle_on_work.second, triangle_on_work.third), tmp_flat);
  207.                 if(angle < max_angle){
  208.                     the_new_point = tmp_point;
  209.                     max_angle = angle;
  210.                 }
  211.             }
  212.         }
  213.         s_tmp.clear();
  214.         s_tmp = {e.first.num,e.second.num,the_new_point.num};
  215.         if(triplets_of_vertices.find(s_tmp) == triplets_of_vertices.end()) {
  216.             triplets_of_vertices.insert(s_tmp);
  217.             Triangle tmp_to_answer(e.first, e.second, the_new_point);
  218.  
  219.             if (e.first.num != 0 && e.second.num != 0 && the_new_point.num != 0) {
  220.                 tmp_to_answer.sort_dots(dots[0]);
  221.             }
  222.             else if (e.first.num != 1 && e.second.num != 1 && the_new_point.num != 1) {
  223.                 tmp_to_answer.sort_dots(dots[1]);
  224.             }
  225.             else if (e.first.num != 2 && e.second.num != 2 && the_new_point.num != 2) {
  226.                 tmp_to_answer.sort_dots(dots[2]);
  227.             }
  228.             else {
  229.                 tmp_to_answer.sort_dots(dots[3]);
  230.             }
  231.             ans.push_back(tmp_to_answer);
  232.             triangles.push(tmp_to_answer);
  233.         }
  234.         if(!triangle_on_work.edges.empty()) {
  235.             triangles.push(triangle_on_work);
  236.         }
  237.     }
  238.     return ans;
  239. }
  240.  
  241. bool compare_triangle(const Triangle& First,const Triangle& Second) {
  242.     if(First.first.num < Second.first.num) {
  243.         return true;
  244.     }
  245.     if(First.first.num > Second.first.num) {
  246.         return false;
  247.     }
  248.     if(First.second.num < Second.second.num) {
  249.         return true;
  250.     }
  251.     if(First.second.num > Second.second.num) {
  252.         return false;
  253.     }
  254.     if(First.third.num <= Second.third.num) {
  255.         return true;
  256.     }
  257.     return false;
  258. }
  259.  
  260. int main() {
  261.     int num_tests = 0;   // Количество тестов
  262.     cin >> num_tests;
  263.  
  264.     for(int test = 0; test < num_tests; test++) {
  265.         int num_dots = 0;   // Количество точек в тесте
  266.         cin >> num_dots;
  267.  
  268.         vector<Point> dots; // Вектор точек в пространстве
  269.  
  270.         // Считываем все точки
  271.         for(int i = 0; i < num_dots; i++) {
  272.             double x = 0;
  273.             double y = 0;
  274.             double z = 0;
  275.             cin >> x >> y >> z;
  276.             Point tmp(x,y,z,i);
  277.             dots.push_back(tmp);
  278.         }
  279.  
  280.         vector<Triangle> convex = Find_Convex(dots); //  Выпуклая оболочка
  281.         std::sort(convex.begin(), convex.end(), compare_triangle);
  282.  
  283.         cout << convex.size() << "\n";  // Вывод данных
  284.         for(auto i:convex) {
  285.             cout << "3 " << i.first.num << " " << i.second.num << " " << i.third.num << "\n";
  286.         }
  287.     }
  288.     return 0;
  289. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement