Advertisement
blufzzz

GiftWrapp (M)

Nov 30th, 2017
109
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 12.79 KB | None | 0 0
  1. #include <iostream>
  2. #include <vector>
  3. #include <memory>
  4. #include <stack>
  5. #include <cmath>
  6. #include <queue>
  7. #include <map>
  8. #include <algorithm>
  9. #include <fstream>
  10.  
  11. using std::cin;
  12. using std::cout;
  13. using std::endl;
  14.  
  15. const double eps = 1e-12;
  16.  
  17.  
  18. template <typename T>
  19. struct Point {
  20.     T x, y, z;
  21.  
  22.     Point(T _x, T _y, T _z):x(_x), y(_y), z(_z) {}
  23.     Point() = default;
  24.     double getAngleFromVertic(Point<T>&& a);
  25.     Point<T> operator * (const Point<T>& point);
  26.     Point<T> operator -();
  27.     Point<T> operator -(const Point<T>& point);
  28.     Point<T> operator +(const Point<T>& point);
  29.     Point<T> operator *(double alpha);
  30.     double scalarMult(const Point<T>& point);
  31.     double length();
  32.  
  33. };
  34.  
  35. template <typename T>
  36. double Point<T>::length() {
  37.     return sqrt(static_cast<double >(x * x + y *y + z * z));
  38. }
  39.  
  40. template <typename T>
  41. Point<T> Point<T>::operator*(const Point &point) {
  42.     return Point((y * point.z - z * point.y),
  43.                         - (x * point.z - z * point.x),
  44.                         (x * point.y - y * point.x));
  45. }
  46.  
  47. template <typename T>
  48. double Point<T>::scalarMult(const Point &point) {
  49.     return x * point.x + y * point.y + z * point.z;
  50. }
  51.  
  52. template <typename T>
  53. Point<T> Point<T>::operator-() {
  54.     return Point(-x, -y, -z);
  55. }
  56.  
  57. template <typename T>
  58. Point<T> Point<T>::operator-(const Point<T> &point) {
  59.     return Point<T>(x - point.x, y - point.y, z - point.z);
  60. }
  61.  
  62. template <typename T>
  63. double Point<T>::getAngleFromVertic(Point<T> &&a) {
  64.     return fabs(static_cast<double >(a.z)/a.length());
  65. }
  66.  
  67. template <typename T>
  68. Point<T> Point<T>::operator+(const Point<T> &point) {
  69.     return Point<T>(x + point.x, y + point.y, z + point.z);
  70. }
  71.  
  72. template <typename T>
  73. Point<T> Point<T>::operator*(double alpha) {
  74.     return Point<T>(x * alpha, y * alpha, z * alpha);
  75. }
  76.  
  77. template <typename T>
  78. struct Flat {
  79.     size_t firstPoint, secondPoint, thirdPoint;
  80.     Point<T> Normal;
  81.     bool operator < (Flat<T>& flat);
  82.     std::tuple<size_t, size_t, size_t> createTuple() const;
  83. };
  84.  
  85. template <typename T>
  86. bool Flat<T>::operator < (Flat<T> &flat) {
  87.     std::tuple<size_t, size_t, size_t> firstTup = createTuple();
  88.     size_t first = std::get<0>(firstTup) * 1000000 + std::get<1>(firstTup) * 1000 + std::get<2>(firstTup);
  89.     std::tuple<size_t, size_t, size_t> secondTup = flat.createTuple();
  90.     size_t second = std::get<0>(secondTup) * 1000000 + std::get<1>(secondTup) * 1000 + std::get<2>(secondTup);
  91.     return first < second;
  92. }
  93.  
  94. template <typename T>
  95. std::tuple<size_t, size_t, size_t> Flat<T>::createTuple() const {
  96.     return std::make_tuple(firstPoint, secondPoint, thirdPoint);
  97. }
  98.  
  99. size_t FindLess(std::tuple<size_t, size_t, size_t> &tuple);
  100.  
  101. size_t FindMax(std::tuple<size_t, size_t, size_t> &tuple);
  102.  
  103. size_t FindMiddle(std::tuple<size_t, size_t, size_t> &tuple);
  104.  
  105. std::tuple<size_t, size_t, size_t> sortTuple(std::tuple<size_t, size_t, size_t> &&Tuple) {
  106.     return std::make_tuple(FindLess(Tuple), FindMax(Tuple), FindMiddle(Tuple));
  107. }
  108.  
  109. size_t FindMiddle(std::tuple<size_t, size_t, size_t> &tuple) {
  110.     size_t first = std::get<0>(tuple);
  111.     size_t second = std::get<1>(tuple);
  112.     size_t third = std::get<2>(tuple);
  113.     size_t sum = first + second + third;
  114.  
  115.     return sum - FindMax(tuple) - FindLess(tuple);
  116. }
  117.  
  118.  
  119. size_t FindMax(std::tuple<size_t, size_t, size_t> &tuple) {
  120.     size_t first = std::get<0>(tuple);
  121.     size_t second = std::get<1>(tuple);
  122.     size_t third = std::get<2>(tuple);
  123.     if (first > second && first > third) {
  124.         return first;
  125.     }
  126.     if (second > first && second > third) {
  127.         return second;
  128.     }
  129.  
  130.     return third;
  131. }
  132.  
  133. size_t FindLess(std::tuple<size_t, size_t, size_t> &tuple) {
  134.     size_t first = std::get<0>(tuple);
  135.     size_t second = std::get<1>(tuple);
  136.     size_t third = std::get<2>(tuple);
  137.     if (first < second && first < third) {
  138.         return first;
  139.     }
  140.     if (second < first && second < third) {
  141.         return second;
  142.     }
  143.  
  144.     return third;
  145. }
  146.  
  147.  
  148. template <typename T>
  149. struct Edge {
  150.     size_t a, b;
  151.     Point<T> normal;
  152.     size_t c;
  153. };
  154.  
  155. template <typename T>
  156. class ConvexHullFinder {
  157. public:
  158.     std::vector<Flat<T>> find(std::vector<Point<T>> &points);
  159.  
  160.     size_t findThirdPoint(std::vector<Point<T>> &points, size_t firstPoint, size_t secondPoint);
  161.  
  162.     Flat<T> FindFirstFlat(std::vector<Point<T>> &points);
  163.  
  164.     std::vector<Flat<T>> FindOtherFlatesUsingFirstOne(Flat<T> &firstFlat, std::vector<Point<T>> &points);
  165.  
  166.     size_t FindSecondPoint(Edge<T> &edge, std::vector<Point<T>> &points);
  167.  
  168.     Flat<T> sortedFlat(Flat<T> &flat, std::vector<Point<T>> &points);
  169.  
  170.     void SortFlates(std::vector<Flat<T>> &flates, std::vector<Point<T>> &points);
  171.  
  172.     void sortAllInsideFlates(std::vector<Flat<T>> &flates, std::vector<Point<T>> &points);
  173. };
  174.  
  175. template <typename T>
  176. std::vector<Flat<T>> ConvexHullFinder<T>::find(std::vector<Point<T>> &points) {
  177.     std::vector<Flat<T>> flates;
  178.  
  179.     Flat<T> firstFlat = FindFirstFlat(points);
  180.  
  181.     flates = FindOtherFlatesUsingFirstOne(firstFlat, points);
  182.  
  183.     SortFlates(flates, points);
  184.  
  185.     return flates;
  186. }
  187.  
  188. template <typename T>
  189. size_t ConvexHullFinder<T>::findThirdPoint(std::vector<Point<T>> &points, size_t firstPoint, size_t secondPoint) {
  190.     for (size_t i = 0; i < points.size(); ++i) {
  191.         Point<T> a = points[secondPoint] - points[firstPoint];
  192.         Point<T> b = points[secondPoint] - points[i];
  193.         Point<T> normal = a * b;
  194.  
  195.         bool CanBeThirdPoint = true;
  196.         if (i != firstPoint && i != secondPoint) {
  197.             double wherePointsAre = 0;
  198.             for (size_t j = 0; j < points.size(); j++) {
  199.                 if (j != firstPoint && j != secondPoint && j != i) {
  200.                     if (wherePointsAre == 0) {
  201.                         wherePointsAre = normal.scalarMult(points[firstPoint] - points[j]);
  202.                     } else if (wherePointsAre * normal.scalarMult(points[firstPoint] - points[j]) < 0) {
  203.                         CanBeThirdPoint = false;
  204.                     }
  205.                 }
  206.             }
  207.             if (CanBeThirdPoint) {
  208.                 return i;
  209.             }
  210.         }
  211.     }
  212. }
  213.  
  214. template <typename T>
  215. Flat<T> ConvexHullFinder<T>::FindFirstFlat(std::vector<Point<T>> &points) {
  216.     size_t MinZPoint = 0;
  217.     for (size_t i = 1; i < points.size(); ++i) {
  218.         if (points[i].z < points[MinZPoint].z) {
  219.             MinZPoint = i;
  220.         }
  221.     }
  222.  
  223.     size_t MaxAnglePoint = (MinZPoint == 0) ? 1 : 0;
  224.  
  225.     for (size_t i = 0; i < points.size(); ++i) {
  226.         if (i != MaxAnglePoint) {
  227.             double FirstAngle = points[MinZPoint].getAngleFromVertic(points[MaxAnglePoint] - points[MinZPoint]);
  228.             double SecondAngle = points[MinZPoint].getAngleFromVertic(points[i] - points[MinZPoint]);
  229.             if (FirstAngle > SecondAngle) {
  230.                 MaxAnglePoint = i;
  231.             } else if (FirstAngle == SecondAngle &&
  232.                        (points[MinZPoint] - points[MaxAnglePoint]).length() < (points[i] - points[MinZPoint]).length()) {
  233.                 MaxAnglePoint = i;
  234.             }
  235.         }
  236.     }
  237.  
  238.     size_t PointOtherPointOnOneSide = findThirdPoint(points, MaxAnglePoint, MinZPoint);
  239.     return Flat<T>{MinZPoint, MaxAnglePoint, PointOtherPointOnOneSide, Point<T>()};
  240. }
  241.  
  242. template <typename T>
  243. std::vector<Flat<T>> ConvexHullFinder<T>::FindOtherFlatesUsingFirstOne(Flat<T> &firstFlat, std::vector<Point<T>> &points) {
  244.  
  245.     std::vector<Flat<T>> flates;
  246.     Point<T> Normal = (points[firstFlat.firstPoint] - points[firstFlat.secondPoint]) *
  247.             (points[firstFlat.thirdPoint] - points[firstFlat.secondPoint]);
  248.  
  249.     if (Normal.z < 0) {
  250.         Normal = -Normal;
  251.     }
  252.  
  253.     firstFlat.Normal = Normal;
  254.     flates.push_back(firstFlat);
  255.  
  256.     std::queue<Edge<T>> edges;
  257.  
  258.     edges.push({firstFlat.firstPoint, firstFlat.secondPoint, Normal, firstFlat.thirdPoint});
  259.     edges.push({firstFlat.secondPoint, firstFlat.thirdPoint, Normal, firstFlat.firstPoint});
  260.     edges.push({firstFlat.firstPoint, firstFlat.thirdPoint, Normal, firstFlat.secondPoint});
  261.  
  262.     std::map<std::tuple<size_t, size_t, size_t>, bool> used;
  263.     used[sortTuple(std::make_tuple(firstFlat.firstPoint, firstFlat.secondPoint, firstFlat.thirdPoint))] = true;
  264.  
  265.     std::map<std::pair<size_t, size_t>, bool> usedEdge;
  266.  
  267.     while (!edges.empty()) {
  268.         Edge<T> edge = edges.front();
  269.         edges.pop();
  270.         if (usedEdge.find(std::make_pair(std::min(edge.a, edge.b), edge.a + edge.b - std::min(edge.a, edge.b))) != usedEdge.end()) {
  271.             continue;
  272.         }
  273.         usedEdge[std::make_pair(std::min(edge.a, edge.b), edge.a + edge.b - std::min(edge.a, edge.b))] = true;
  274.         size_t secondPoint = FindSecondPoint(edge, points);
  275.         Normal = (points[edge.a] - points[edge.b]) * (points[secondPoint] - points[edge.b]);
  276.  
  277.         if (Normal.scalarMult(points[firstFlat.firstPoint] - points[secondPoint]) < 0 ||
  278.                 Normal.scalarMult(points[firstFlat.secondPoint] - points[secondPoint]) < 0 ||
  279.                 Normal.scalarMult(points[firstFlat.thirdPoint] - points[secondPoint]) < 0 ) {
  280.             Normal = -Normal;
  281.         }
  282.         if (used.find(sortTuple(std::make_tuple(edge.a, edge.b, secondPoint))) == used.end()) {
  283.             flates.push_back(Flat<T>{edge.a, edge.b, secondPoint, Normal});
  284.             used[sortTuple(std::make_tuple(edge.a, edge.b, secondPoint))] = true;
  285.             Edge<T> firstEdge{edge.a, secondPoint, Normal, edge.b};
  286.             Edge<T> secondEdge{edge.b, secondPoint, Normal, edge.a};
  287.             edges.push(firstEdge);
  288.             edges.push(secondEdge);
  289.         }
  290.  
  291.     }
  292.  
  293.     return flates;
  294. }
  295.  
  296. template <typename T>
  297. void ConvexHullFinder<T>::SortFlates(std::vector<Flat<T>>& flates, std::vector<Point<T>> &points) {
  298.     sortAllInsideFlates(flates, points);
  299.     std::sort(flates.begin(), flates.end(), [](const Flat<T>& a, const Flat<T>& b) {
  300.         std::tuple<size_t, size_t, size_t> firstTup = a.createTuple();
  301.         size_t first = std::get<0>(firstTup) * 100000000 + std::get<1>(firstTup) * 10000 + std::get<2>(firstTup);
  302.         std::tuple<size_t, size_t, size_t> secondTup = b.createTuple();
  303.         size_t second = std::get<0>(secondTup) * 100000000 + std::get<1>(secondTup) * 10000 + std::get<2>(secondTup);
  304.         return first < second;
  305.     });
  306. }
  307.  
  308. template <typename T>
  309. size_t ConvexHullFinder<T>::FindSecondPoint(Edge<T> &edge, std::vector<Point<T>> &points) {
  310.  
  311.     size_t PointMinAngle = points.size();
  312.     double minScalar = -1;
  313.     for (size_t i = 0; i < points.size(); ++i) {
  314.         if (i != edge.a && i != edge.b && i != edge.c) {
  315.             Point<T> normal = (points[edge.a] - points[edge.b]) * (points[i] - points[edge.a]);
  316.             if (normal.scalarMult(points[edge.c] - points[i]) > eps) {
  317.                 normal = -normal;
  318.             }
  319.             double tempAngle = normal.scalarMult(edge.normal) / normal.length();
  320.             if (PointMinAngle == points.size() || (PointMinAngle != points.size() && tempAngle < minScalar)) {
  321.                 PointMinAngle = i;
  322.                 minScalar = tempAngle;
  323.             }
  324.         }
  325.     }
  326.     return PointMinAngle;
  327. }
  328.  
  329. template <typename T>
  330. void ConvexHullFinder<T>::sortAllInsideFlates(std::vector<Flat<T>>& flates, std::vector<Point<T>> &points) {
  331.     for (Flat<T>& flat : flates) {
  332.         flat = sortedFlat(flat, points);
  333.     }
  334. }
  335.  
  336.  
  337.  
  338. template <typename T>
  339. Flat<T> ConvexHullFinder<T>::sortedFlat(Flat<T> &flat, std::vector<Point<T>> &points) {
  340.     std::tuple<size_t, size_t, size_t> tuple = flat.createTuple();
  341.     size_t firstPoint = FindLess(tuple);
  342.     size_t secondPoint = FindMax(tuple);
  343.     size_t thirdPoint= FindMiddle(tuple);
  344.  
  345.     Point<T> first = points[secondPoint] - points[firstPoint];
  346.     Point<T> second = points[thirdPoint] - points[firstPoint];
  347.     if ((first * second).scalarMult(flat.Normal) > eps) {
  348.         std::swap(secondPoint, thirdPoint);
  349.     }
  350.  
  351.     return Flat<T>{firstPoint, secondPoint, thirdPoint, flat.Normal};
  352. }
  353.  
  354.  
  355. int main() {
  356.     freopen("input.txt", "r", stdin);
  357.     freopen("output.txt", "w", stdout);
  358.  
  359.     size_t TestCount;
  360.     cin >> TestCount;
  361.  
  362.     for (size_t i = 0; i < TestCount; ++i) {
  363.         size_t PountCount;
  364.         cin >> PountCount;
  365.  
  366.         std::vector<Point<double>> points(PountCount);
  367.  
  368.         for (size_t j = 0; j < PountCount; ++j) {
  369.             cin >> points[j].x >> points[j].y >> points[j].z;
  370.         }
  371.  
  372.         std::shared_ptr<ConvexHullFinder<double >> convexHullFinder(new ConvexHullFinder<double >);
  373.  
  374.         std::vector<Flat<double>> convexHull = convexHullFinder->find(points);
  375.  
  376.         cout << convexHull.size() << endl;
  377.  
  378.         for (size_t j = 0; j < convexHull.size(); ++j) {
  379.             cout << 3 << " ";
  380.             cout << convexHull[j].firstPoint << " " << convexHull[j].secondPoint << " " << convexHull[j].thirdPoint << endl;
  381.         }
  382.     }
  383. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement