Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- #include <iostream>
- #include <string>
- #include <fstream>
- #include <iomanip>
- #include <math.h>
- using namespace std;
- // Структура точки в 3D
- struct Vec3 {
- double x, y, z;
- Vec3() {
- x = 0, y = 0, z = 0;
- }
- Vec3(double x, double y, double z) {
- this->x = x;
- this->y = y;
- this->z = z;
- }
- double get_distance(const Vec3* p2);
- void print(int SetW = 4, int SetPrecision = 2);
- };
- // Получение расстояния между двумя точками
- double Vec3::get_distance(const Vec3* p2) {
- return sqrt(pow(this->x - p2->x, 2) + pow(this->y - p2->y, 2) + pow(this->z - p2->z, 2));
- }
- // Вывод координат точки в консоль
- void Vec3::print(int SetW, int SetPrecision) {
- cout << setw(SetW) << setprecision(SetPrecision) << this->x << " ";
- cout << setw(SetW) << setprecision(SetPrecision) << this->y << " ";
- cout << setw(SetW) << setprecision(SetPrecision) << this->z << endl;
- }
- // Структура треугольника (содержит: 3 точки и свой периметр)
- struct Triangle {
- Vec3* v1, * v2, * v3;
- double perimeter;
- void update_perimeter();
- Triangle() {
- v1 = NULL; v2 = NULL; v3 = NULL;
- perimeter = -DBL_MAX; // Самое малое double
- }
- Triangle(Vec3* p1, Vec3* p2, Vec3* p3) {
- v1 = p1; v2 = p2; v3 = p3;
- update_perimeter();
- }
- void print(int SetW = 4, int SetPrecision = 2);
- };
- // Функция для обновления периметра, при изменении точек (ручной вызов)
- void Triangle::update_perimeter() {
- this->perimeter = v1->get_distance(v2) + v2->get_distance(v3) + v3->get_distance(v1);
- }
- // Вывод координат всех точек треугольника
- void Triangle::print(int SetW, int SetPrecision) {
- cout << endl;
- this->v1->print(SetW, SetPrecision);
- this->v2->print(SetW, SetPrecision);
- this->v3->print(SetW, SetPrecision);
- }
- // Функция для получения случайного double в диапазоне
- double fRand(double fMin, double fMax)
- {
- double f = (double)rand() / RAND_MAX;
- return fMin + f * (fMax - fMin);
- }
- // Функция для удобного создания файла с <pcount> кол-вом точек со случайными координатами
- void createRandPoints(long pcount = 3, double dMin = -100.0, double dMax = 100.0) {
- ofstream out("points.txt");
- if (pcount < 3)
- pcount = 3;
- out << pcount << endl;
- for (int i = 0; i < pcount; i++)
- out << fRand(dMin, dMax) << " " << fRand(dMin, dMax) << " " << fRand(dMin, dMax) << endl;
- out.close();
- }
- // Реализация "сочетания" C(m,n)
- long long unsigned int Combination(const int m, const int n) {
- long long unsigned int fn = 1, dn = 1;
- const int nm = n - m;
- for (int i = 1; i <= n; i++) {
- if (i <= m)
- dn *= i;
- if (i > nm)
- fn *= i;
- if (fn % dn == 0) {
- fn /= dn;
- dn = 1;
- }
- }
- return fn / dn;
- }
- // Главная ф-ция
- int main() {
- long pointCount; string temp;
- // createRandPoints(1000);
- ifstream in("points.txt");
- if (!in) return 0; // Файл пуст
- in >> temp;
- pointCount = stoi(temp);
- // Основной массив, хранящий точки
- Vec3* points = new Vec3[pointCount];
- // Заполнение массива из файла
- for (Vec3* p = points; p < points + pointCount; p++) {
- in >> temp;
- p->x = stod(temp);
- in >> temp;
- p->y = stod(temp);
- in >> temp;
- p->z = stod(temp);
- }
- in.close();
- // Временный треугольник
- auto t = new Triangle(new Vec3(), new Vec3(), new Vec3());
- // Треугольник с минимальным периметром
- Triangle minTris = Triangle();
- // Ставим ему максимальное возможное значение периметра (т.к. по стандарту оно минимально)
- minTris.perimeter = -minTris.perimeter;
- /*
- Реализация системы загрузки в процентах (pointCount < 4010)
- */
- // Счётчик кол-ва треугольников
- long long unsigned int q = 0;
- // Кол-во треугольников
- const long long unsigned int trisCount = Combination(3, pointCount);
- // Условие включения загрузки
- const bool enableLoading = trisCount > 10000000;
- // Деление процентов (прим 5%, 10%, 15%)
- const int showByPrecents = 5;
- // Количество треугольников для вывода процентов в консоль
- const long long unsigned int onePrecentPiece = trisCount / (100 / showByPrecents);
- // Счётчик процентов
- int precent = 0;
- /*
- Самая эффективная реализация перебора всех сочетаний точек
- в порядке возрастания адреса (чтение из массива)
- не допускающая попадание одинаковых точек в один треугольник
- */
- for (auto p1 = points; p1 < points + (pointCount - 2); p1++) {
- t->v1 = p1;
- for (auto p2 = p1 + 1; p2 < points + (pointCount - 1); p2++) {
- t->v2 = p2;
- for (auto p3 = p2 + 1; p3 < points + (pointCount); p3++) {
- t->v3 = p3;
- q++;
- // Сравнение периметров временного и минимального
- t->update_perimeter();
- if (minTris.perimeter > t->perimeter)
- minTris = *t;
- // Реализация "загрузки"
- if (enableLoading)
- if (q % onePrecentPiece == 0) {
- precent += showByPrecents;
- cout << precent << " %" << endl;
- }
- /* Раздельный if используется для экономии расчётов,
- т.к. если загрузка не нужна, то будет лишним проводить
- деление с остатком и его последуещее сравнение
- */
- }
- }
- }
- // Вывод результата
- cout << "Tris count: " << q << endl;
- cout << "Min perimiter: " << minTris.perimeter << endl;
- cout << "Of triangle: ";
- minTris.print(5, 3);
- return 0;
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement