Скачать презентацию Красно-чёрное дерево двоичное дерево поиска в котором Скачать презентацию Красно-чёрное дерево двоичное дерево поиска в котором

AISD ANSWERS.pptx

  • Количество слайдов: 30

Красно-чёрное дерево — двоичное дерево поиска, в котором каждый узел имеет атрибут цвет, принимающий Красно-чёрное дерево — двоичное дерево поиска, в котором каждый узел имеет атрибут цвет, принимающий значения красный или черный. В дополнение к обычным требованиям, налагаемым на двоичные деревья поиска, к красночёрным деревьям применяются следующие требования: -Корень — чёрный. (В других определениях это правило иногда опускается. Это правило слабо влияет на анализ, так корень всегда может быть изменен с красного на чёрный, но не обязательно наоборот). -Все листья(NIL) — черные. -Оба потомка каждого красного узла — черные. -Всякий простой путь от данного узла до любого листового узла, являющегося его потомком, содержит одинаковое число черных узлов.

Вставка элемента КЧД 1. Вставка элемента КЧД 1. "Дядя" этого узла тоже красный. Тогда просто перекрашиваем "отца" и "дядю" в чёрный цвет, а "деда" - в красный. Проверяем, не нарушает ли он теперь балансировку. Если в результате этих перекрашиваний мы дойдём до корня, то в нём в любом случае ставим чёрный цвет. 2. "Дядя" чёрный. Если выполнить только перекрашивание, то может нарушиться постоянство чёрной высоты дерева по всем ветвям. Поэтому выполняем поворот. Если добавляемый узел был правым потомком, то необходимо сначала выполнить левое вращение, которое сделает его левым потомком. Удаление вершины КЧД При удалении вершины могут возникнуть три случая в зависимости от количества её детей: - Если у вершины нет детей, то изменяем указатель на неё у родителя на nil - Если у неё только один ребёнок, то делаем у родителя ссылку на него вместо этой вершины. - Если же имеются оба ребёнка, то находим вершину со следующим значением ключа. У такой вершины нет левого ребёнка. Удаляем уже эту вершину описанным во втором пункте способом, скопировав её ключ в изначальную вершину.

B-дерево является идеально сбалансированным, то есть глубина всех его листьев одинакова. B-дерево имеет следующие B-дерево является идеально сбалансированным, то есть глубина всех его листьев одинакова. B-дерево имеет следующие свойства (t — параметр дерева, называемый минимальной степенью B-дерева, не меньший 2. ): Каждый узел, кроме корня, содержит не менее t-1 ключей, и каждый внутренний узел имеет по меньшей мере t дочерних узлов. Если дерево не является пустым, корень должен содержать как минимум один ключ. Каждый узел, кроме корня, содержит не более 2 t-1 ключей и не более чем 2 t сыновей во внутренних узлах Корень содержит от 1 до 2 t-1 ключей, если дерево не пусто и от 2 до 2 t детей при высоте большей 0. Каждый узел дерева, кроме листьев, содержащий ключи K 1, …, Kn, имеет n+1 сына. i-й сын содержит ключи из отрезка [Ki-1; Ki], K 0 = - беск. , Kn+1 = беск. Ключи в каждом узле упорядочены по неубыванию. Все листья находятся на одном уровне.

2 -3 -дерево является идеально сбалансированным деревом поиска. Все пути от корня до любого 2 -3 -дерево является идеально сбалансированным деревом поиска. Все пути от корня до любого листа имеют одинаковую длину. - Узлы дерева делятся на два вида - внутренние и листья. - Элементы множества располагаются только в листьях дерева в линейном возрастающем порядке. - Внутренний узел имеет 2 или 3 сына (son 1, son 2, son 3). - В каждый внутренний узел записывается ключ наименьшего элемента (low 2), являющегося потомком второго сына и ключ наименьшего элемента – потомка третьего сына (low 3), если третий сын есть. Поиск элемента в 2 – 3 дереве Элемент можно найти за время O(log 2 n), сравнивая ключ искомого элемента с параметрами в узлах. Если ключ меньше, чем минимальный элемент у второго сына, то выбирается первый сын. Иначе, если узел имеет двух сыновей, выбирается второй сын. Если есть третий сын, то выбирается второй сын, если ключ меньше минимального ключа третьего сына, или третий сын в противном случае. Таким образом, поиск приводит к листу с искомым ключом. Удаление элемента из 2 – 3 дерева Если при удалении узла x у родителя - у останется один сын и узел у является корнем, то родитель удаляется из дерева, а корнем становится его единственный сын. Пусть родитель не является корнем. Тогда, если братья узла у имеют трех сыновей, то один из этих сыновей передаются узлу у, и у него становится двое сыновей. Если братья имеют двух сыновей, то единственный сын узла у передается одному из братьев в качестве третьего сына. Узел у после этого удаляется. Если после этого у родителя удаленного узла у останется один сын, то процесс перестройки повторяется для него.

Алгоритм Рабина. Карпа O(n) Алгоритм Кнута. Морриса-Пратта <длина Хэширование позволяет серьёзно искомой+длина O(hn) снизить Алгоритм Рабина. Карпа O(n) Алгоритм Кнута. Морриса-Пратта <длина Хэширование позволяет серьёзно искомой+длина O(hn) снизить сложность в среднем входной O(n) Алгоритм Ахо-Корасик O(n*алфа вит) Алгоритм Бойера. Мура O(n+ал фавит) ≤ 2 h+1 =длине строки <длина входной O(hn) Один из первых алгоритмов с линейной оценкой в худшем случае Строит конечный автомат, который распознаёт язык, состоящий из одной -единственной строки. После небольшой модификации позволяет за один проход по длине строки найти одну строку из нескольких. Стандартный алгоритм поиска подстроки в строке

Нагруженное дерево — структура данных реализующая интерфейс ассоциативного массива, то есть позволяющая хранить пары Нагруженное дерево — структура данных реализующая интерфейс ассоциативного массива, то есть позволяющая хранить пары «ключ-значение» . Суффиксное дерево — бор, содержащий все суффиксы некоторой строки (и только их). Позволяет выяснять, входит ли строка w в исходную строку t, за время O(|w|), где |w| — длина строки w. Неявное суффиксное дерево строки S — это дерево, полученное из суффиксного дерева S$ удалением всех вхождений терминального символа $ из меток дуг дерева, удалением после этого дуг без меток и удалением затем вершин, имеющих меньше двух детей. Неявное суффиксное дерево префикса S[l. . i] строки S аналогично получается из суффиксного дерева для S[l. . i]$ удалением символов $, дуг и вершин, как описано выше. Дана строка S[0…n-1] длины n. i-ым суффиксом строки называется подстрока S[i…n-1], i=0, …, n-1. Тогда суффиксным массивом строки S называется перестановка индексов суффиксов p[0, …, n-1], p[i] € [0; n-1], которая задаёт порядок суффиксов в порядке лексикографической сортировки. Иными словами, нужно выполнить сортировку всех суффиксов заданной строки.

Суффиксное дерево. Алгоритм Укконена строит суффиксное дерево, добавляя в него по одной букве. Текущая Суффиксное дерево. Алгоритм Укконена строит суффиксное дерево, добавляя в него по одной букве. Текущая позиция в дереве соответствует максимальному неполному суффиксу уже добавленных букв, который уже встречался где-то раньше. Так, для строки aaababaab таким суффиксом будет aab. Псевдокод добавления буквы в дерево выглядит следующим образом: пока из текущей позиции нельзя сходить по данной букве | если нет вершины в текущей позиции | | добавить вершину и построить суффиксную ссылку | +------ | пройти по суффиксной ссылке +---- сходить по данной букве При этом на рёбрах, ведущих в листья, индекс последней буквы надо проставлять +беск. Как несложно заметить, алгоритм Укконена является on-line алгоритмом приписывании букв в конец строки.

Поиск в нагруженном дереве О(|Key|) Пусть дан ключ Key, который необходимо найти в дереве. Поиск в нагруженном дереве О(|Key|) Пусть дан ключ Key, который необходимо найти в дереве. Будем спускаться из корня дерева на нижние уровни, каждый раз переходя в узел, чья метка совпадает с очередным символом ключа. После того как обработаны все символы ключа, узел, в котором остановился спуск и будет искомым узлом. Если в процессе спуска не нашлось узла с меткой, соответствующей очередному символу ключа, или спуск остановился на промежуточной вершине (вершине, не имеющей значения), то искомый ключ отсутствует в дереве. Вставка в нагруженное дерево О(|Key|) Пусть дана пара из ключа Key и значения Value, которую нужно добавить. Как и в алгоритме поиска ключа, будем спускаться из корня дерева на нижние уровни, каждый раз переходя в узел, чья метка совпадает с очередным символом ключа. После того как обработаны все символы ключа, узел, в котором остановился спуск и будет узлом, которому должно быть присвоено значение Value (также, разумеется, узел должен быть помечен как имеющий значение). Если в процессе спуска отсутствует узел с меткой, соответствующей очередному символу ключа, то следует создать новый промежуточный узел с нужной меткой и назначить его потомком текущего.

char *s; // входная строка ///////СУФФИКСНЫЙ МАССИВ int n; // длина строки const int char *s; // входная строка ///////СУФФИКСНЫЙ МАССИВ int n; // длина строки const int maxlen =. . . ; // максимальная длина строки const int alphabet = 256; // размер алфавита, <= maxlen int p[maxlen], cnt[maxlen], c[maxlen]; memset (cnt, 0, alphabet * sizeof(int)); for (int i=0; i=0; --i) p[--cnt[c[pn[i]]]] = pn[i]; cn[p[0]] = 0; classes = 1; for (int i=1; i

Дана строка S[0…n-1]. Требуется вычислить для неё префикс-функцию, т. е. массив чисел π [0…n-1], Дана строка S[0…n-1]. Требуется вычислить для неё префикс-функцию, т. е. массив чисел π [0…n-1], где π[i] определяется следующим образом: это такая наибольшая длина наибольшего собственного суффикса подстроки S[0…i], совпадающего с её префиксом (собственный суффикс — значит не совпадающий со всей строкой). В частности, значение π[0] полагается равным нулю. Математически определение префикс-функции можно записать следующим образом: π[i] = max {k: S[0…k-1] = S[i – k + 1…i]} k=0…I Приведём здесь итоговую схему алгоритма Кнута-Морриса-Пратта: Считать значения префикс-функции П[i] будем по очереди: от i=1 к i=n 1 (значение П[0] просто присвоим равным нулю). Для подсчёта текущего значения П[i] мы заводим переменную j, обозначающую длину текущего рассматриваемого образца. Изначально j= П[i-1]. Тестируем образец длины j, для чего сравниваем символы S[j] и S[i]. Если они совпадают — то полагаем П[i]=j+1 и переходим к следующему индексу i+1. Если же символы отличаются, то уменьшаем длину j, полагая её равной П[j – 1], и повторяем этот шаг алгоритма с начала. Если мы дошли до длины j=0 и так и не нашли совпадения, то останавливаем процесс перебора образцов и полагаем П[i]=0 и переходим к следующему индексу i+1.

Алгоритм К-М-П vector<int> prefix_function (string s) { int n = (int) s. length(); vector<int> Алгоритм К-М-П vector prefix_function (string s) { int n = (int) s. length(); vector pi (n); for (int i=1; i 0 && s[i] != s[j]) j = pi[j-1]; if (s[i] == s[j]) ++j; pi[i] = j; } return pi; } Простейший алгоритм поиска подстроки for(int i =0; i<= haystack. Length - needle. Length; i++) { for (int j = 1; j

Алгоритм БМ vector<int> prefix_func(const string &s) { vector<int> p(s. length()); int k = 0; Алгоритм БМ vector prefix_func(const string &s) { vector p(s. length()); int k = 0; p[0] = 0; for (int i = 1; i < s. length(); ++i) { while (k > 0 && s[k] != s[i]) { k = p[k - 1]; } if (s[k] == s[i]) { ++k; } p[i] = k; } return p; }

int find(string &s, string &t) { if (s. length() < t. length()) { return int find(string &s, string &t) { if (s. length() < t. length()) { return -1; } if (!t. length()) { return s. length(); } typedef hash_map TStop. Table; typedef hash_map TSuffics. Table; TStop. Table stop_table; TSuffics. Table suffics_table; for (int i = 0; i < t. length(); ++i) { stop_table[t[i]] = i; } string rt(t. rbegin(), t. rend()); vector p = prefix_func(t), pr = prefix_func(rt); for (int i = 0; i < t. length() + 1; ++i) { suffics_table[i] = t. length() - p. back(); } for (int i = 1; i < t. length(); ++i) { int j = pr[i]; suffics_table[j] = min(suffics_table[j], i - pr[i] + 1); } for (int shift = 0; shift <= s. length() - t. length(); ) { int pos = t. length() - 1; while (t[pos] == s[pos + shift]) { if (pos == 0) return shift; --pos; } if (pos == t. length() - 1) { TStop. Table: : const_iterator stop_symbol = stop_table. find(s[pos + shift]); int stop_symbol_additional = pos - (stop_symbol != stop_table. end() ? stop_symbol->second : -1); shift += stop_symbol_additional; } else { shift += suffics_table[t. length() - pos - 1]; } return -1; }

Пусть дана строка S длины n. Тогда Z-функция от этой строки — это массив Пусть дана строка S длины n. Тогда Z-функция от этой строки — это массив длины n, i-ый элемент которого равен наибольшему числу символов, начиная с позиции i, совпадающих с первыми символами строки S. Иными словами, Z[i] — это наибольший общий префикс строки S и её i-го суффикса. Формальное определение можно представить в виде следующей элементарной реализации за O(n 2): vector z_function_trivial (string s) { int n = (int) s. length(); vector z (n); for (int i=1; i

Пусть дан набор строк в алфавите размера k суммарной длины m. Алгоритм Ахо-Корасик строит Пусть дан набор строк в алфавите размера k суммарной длины m. Алгоритм Ахо-Корасик строит для этого набора строк структуру данных "бор", а затем по этому бору строит автомат, всё за O(m) времени и O(mk) памяти. Построение бора: struct vertex { int next[K]; bool leaf; }; vertex t[NMAX+1]; int sz; memset (t[0]. next, 255, sizeof t[0]. next); sz = 1; void add_string (const string & s) { int v = 0; for (size_t i=0; i

Алгоритм Ахо-Корасика struct vertex { int next[K]; bool leaf; int p; char pch; int Алгоритм Ахо-Корасика struct vertex { int next[K]; bool leaf; int p; char pch; int link; int go[K]; }; vertex t[NMAX+1]; int sz; void init() { t[0]. p = t[0]. link = -1; memset (t[0]. next, 255, sizeof t[0]. next); memset (t[0]. go, 255, sizeof t[0]. go); sz = 1; } void add_string (const string & s) { int v = 0; for (size_t i=0; i

 А-К продолжение int go (int v, char c); int get_link (int v) { А-К продолжение int go (int v, char c); int get_link (int v) { if (t[v]. link == -1) if (v == 0 || t[v]. p == 0) t[v]. link = 0; else t[v]. link = go (get_link (t[v]. p), t[v]. pch); return t[v]. link; } int go (int v, char c) { if (t[v]. go[c] == -1) if (t[v]. next[c] != -1) t[v]. go[c] = t[v]. next[c]; else t[v]. go[c] = v==0 ? 0 : go (get_link (v), c); return t[v]. go[c]; }

Алгоритм Рабина – Карпа Дана строка S и текст T, состоящие из маленьких латинских Алгоритм Рабина – Карпа Дана строка S и текст T, состоящие из маленьких латинских букв. Требуется найти все вхождения строки S в текст T за время O (|S| + |T|). Алгоритм. Посчитаем хэш для строки S. Посчитаем значения хэшей для всех префиксов строки T. Теперь переберём все подстроки T длины |S| и каждую сравним с |S|. string s, t; // входные данные // считаем все степени p const int p = 31; vector p_pow (max (s. length(), t. length())); p_pow[0] = 1; for (size_t i=1; i h (t. length()); for (size_t i=0; i

Таблицы с прямой адресацией Прямая адресация представляет собой простейшую технологию, которая хорошо работает для Таблицы с прямой адресацией Прямая адресация представляет собой простейшую технологию, которая хорошо работает для небольших множеств ключей. Предположим, что приложению требуется динамическое множество, каждый элемент которого имеет ключ из множества U = {0, 1, . . . , т — 1}, где т не слишком велико. Кроме того, предполагается, что никакие два элемента не имеют одинаковых ключей. Для представления динамического множества мы используем массив, или таблицу с прямой адресацией, который обозначим как Т [О. . т — 1], каждая позиция, или ячейка (position, slot), которого соответствует ключу из пространства ключей U.

Динамическое программирование — способ решения сложных задач путём разбиения их на более простые подзадачи. Динамическое программирование — способ решения сложных задач путём разбиения их на более простые подзадачи. Динамическое программирование, как правило, применяется к задачам оптимизации. В таких задачах возможно наличие многих решений. Каждому варианту решения можно сопоставить какое-то значение, и нам нужно найти среди них решение с оптимальным (минимальным или максимальным) значением. Процесс разработки алгоритмов динамического программирования можно раз - бить на четыре перечисленных ниже этапа. 1. Описание структуры оптимального решения. 2. Рекурсивное определение значения, соответствующего оптимальному решению. 3. Вычисление значения, соответствующего оптимальному решению, с помощью метода восходящего анализа. 4. Составление оптимального решения на основе информации, полученной на

Рассмотрим последовательность чисел a 1, a 2, …, an. Если вычеркнуть из этой последовательности Рассмотрим последовательность чисел a 1, a 2, …, an. Если вычеркнуть из этой последовательности часть чисел, мы получим другую последовательность, которую называют подпоследовательностью данной последовательности. Рассмотрим теперь еще одну последовательность b 1, b 2, …, bm. Требуется найти длину самой длинной подпоследовательности {a. I}, которая одновременно является и подпоследовательностью последовательности {b. I}. Такую последовательность называют наибольшей общей подследовательностью (НОП). Например, для последовательностей 1, 2, 3, 4, 5 и 2, 7, 3, 2, 5 НОП является подпоследовательность 2, 3, 5, состоящая из трёх членов. Будем решать эту задачу методом динамического программирования. Для этого опишем подзадачи, на которые мы будем разбивать нашу задачу. Мы напишем функцию LCS(p, q), которая находит длину НОП для двух начальных участков a 1, …, ap и b 1, …, bq наших последовательностей. Пусть для всех пар q и p (p < n, q < m), мы задачу решать уже научились. Попробуем вычислить LCS(n, m). Рассмотрим два случая: 1) an= bm. Тогда LCS(n, m)=LCS(n-1, m-1)+1. 2) an≠ bm. Тогда LCS(n, m)=max(LCS(n, m-1), LCS(n-1, m)). Пользуясь этими формулами, мы можем заполнить таблицу значений LCS(p, q) для всех p и q последовательно: сначала заполняем первую строчку слева направо, затем вторую и т. д. Последнее число в последней строке и будет ответом на поставленную задачу. Данный алгоритм требует порядка O(nm) операций.

Выпуклой оболочкой множества точек Q называется наименьший выпуклый многоугольник Р, такой что каждая точка Выпуклой оболочкой множества точек Q называется наименьший выпуклый многоугольник Р, такой что каждая точка из Q находится либо на границе многоугольника Р, либо в его внутренней области. Обозначим выпуклую оболочку множества Q как CH(Q). В методе сканирования по Грэхему задача о выпуклой оболочке решается с помощью стека S, сформированного из точек-кандидатов. Все точки входного множества Q заносятся в стек, а потом точки, не являющиеся вершинами СН (Q), со временем удаляются из него. По завершении работы алгоритма в стеке S остаются только вершины оболочки СН (Q) в порядке их обхода против часовой стрелки. В качестве входных данных процедуры Graham_Scan выступает множество точек Q, где |Q| >= 3. В ней вызывается функция Top(S), которая возвращает точку, находящуюся на вершине стека S, не изменяя при этом его содержимое. Кроме того, используется также функция Next_To_Top. E), которая возвращает точку, расположенную в стеке S на одну позицию ниже от верхней точки; стек S при этом не изменяется. Вскоре будет показано, что стек S, возвращаемый процедурой Graham_Scan, содержит только вершины СН (Q), причем расположенные в порядке обхода против часовой стрелки, если просматривать их в стеке снизу вверх.

1) Пусть р0 — точка из множества Q с минимальной координатой у или самая 1) Пусть р0 — точка из множества Q с минимальной координатой у или самая левая из таких точек при наличии совпадений 2) Пусть (p 1, p 2, …, pm) — остальные точки множества Q, отсортированные в порядке возрастания полярного угла, измеряемого против часовой стрелки относительно точки р0(если полярные углы нескольких точек совпадают, то из множества удаляются все эти точки, кроме одной, самой дальней от точки р0) 3) Push(p 0, S) 4) Push(p 1, S) 5) Push(p 2, S) 6) for i <— 3 to m 7) do while (пока) угол, образованный точками Next_To_Top(S), Top(S) и pi, образует не левый поворот (при движении по ломаной, образованной этими точками, мы движемся прямо или вправо) 8) do Pop(S) 9) Push(pi, S) 10) return S

Алгоритм Джарвиса Пусть дано множество P= {p 1, p 2, …, p. N} точек. Алгоритм Джарвиса Пусть дано множество P= {p 1, p 2, …, p. N} точек. В качестве начальной берётся самая левая нижняя точка p 1 (ее можно найти за O(N) обычным проходом по всем точкам), она точно является вершиной выпуклой оболочки. Затем для каждой точки pi ищется против часовой стрелки точка pi+1 путём нахождения за O(N) среди оставшихся точек (+ самая левая нижняя) точки с наименьшим полярным углом pi-1 pipi+1. Она и будет следующей вершиной выпуклой оболочки. При этом сам угол не обязательно вычислять, достаточно вычислить векторное произведение между лучами pip’i+1 и pip”i+1, где p’i+1 найденный на данный момент минимум, p”i+1 - претендент (первым минимумом может быть выбрана любая точка). Если векторное произведение отрицательно, то найден новый минимум. Если равно нулю, то есть p’i+1 и p”i+1 лежат на одной прямой, то минимум та, которая лежит дальше от точки pi. Алгоритм продолжается пока pi+1 ≠ p 1. Алгоритм остановится, потому что самая левая нижняя точка в любом случае принадлежит выпуклой оболочке.

Алгоритм быстрой оболочки - множество точек разбивается на два подмножества, каждое из которых будет Алгоритм быстрой оболочки - множество точек разбивается на два подмножества, каждое из которых будет содержать одну из ломаных, соединение которых дает многоугольник выпуклой оболочки. 1) Возьмем две крайние точки множества S — левую Л и правую П. Проведем прямую через них. Обозначим через S 1 подмножество точек, расположенных выше или на прямой, проходящей через точки Л и П, а через S 2 — подмножество точек, расположенных ниже или на той же прямой. 2) Рассмотрим верхнее подмножество S 1. Выберем точку Pi, имеющую наибольшее расстояние от прямой ЛП (треугольник ЛPi. П имеет наибольшую площадь). . Если таких точек несколько, выбираем ту, у которой угол Pi. ЛП наибольший. Точка Pi является вершиной выпуклой оболочки множества. В самом деле, если через точку Pi провести прямую, параллельную прямой ЛП, то выше этой прямой не окажется ни одной точки множества S. Возможно, на построенной прямой окажутся другие точки, но, согласно сделанному выбору, Pi из них самая левая. Т. о. Точка Pi не может быть представлена выпуклой комбинацией двух других точек множества S. Построим прямые ЛPi и Pi. П. Точки, расположенные справа от обеих прямых, могут быть исключены из дальнейшего рассмотрения, поскольку они являются внутренними точками треугольника ЛPi. П, то есть не принадлежат CH(S) — границе выпуклой оболочки. 3) Теперь рассмотрим подмножество точек S 11, расположенных слева от прямой ЛPi или на ней, и подмножество точек S 12, расположенных слева от прямой Pi. П или на ней. Для каждого из подмножеств строим выпуклую оболочку. Выпуклая оболочка множества S 1 образуется склейкой упорядоченных списков вершин CH(S 11) и CH(S 12). 4) Решаем задачу для S 2.

Матроид — это упорядоченная пара М = (S, χ), удовлетворяющая сформулированным ниже условиям: 1) Матроид — это упорядоченная пара М = (S, χ), удовлетворяющая сформулированным ниже условиям: 1) Множество S конечное. 2) χ — непустое семейство подмножества S (которые называются независимыми подмножествами), таких что, если В € χ и А С В, то A € χ. Если семейство χ удовлетворяет этому свойству, то его называют наследственным (hereditary). Заметим, что пустое множество 0 с необходимостью принадлежит семейству χ. 3) Если A € χ, В € χ и |А| < |В|, то существует такой элемент х € А — B, 4) что A U {х} € χ. Говорят, что структура М удовлетворяет свойству замены. Т 1 Если G = (V, Е) — неориентированный граф, то MG = (SG, χ G) - матроид. T 2 Все максимальные независимые подмножества матроида имеют один и тот же размер.

Триангуляция называется оптимальной, если сумма длин всех ребер минимальна среди всех возможных триангуляций, построенных Триангуляция называется оптимальной, если сумма длин всех ребер минимальна среди всех возможных триангуляций, построенных на тех же исходных данных. Задача построения оптимальной триангуляции является NP-полной. Используем алгоритм полного перебора в глубину всех возможных триангуляций. 1. Во множество исходных точек помещаются концы всех структурных ребер. 2. Генерируются ребра, соединяющие все пары точек, ребра сортируются по длине (обозначим их количество M). 3. В триангуляцию вставляются все отрезки структурных линий. Вычисляется суммарная длина всех ребер S в триангуляции. Устанавливается минимальная достигнутая сумма всех ребер Smax=+∞. 4. Следующие шаги выполняются рекурсивно, начиная с первого (k=1) элемента отсортированного множества ребер из шага 2. 4. 1. Пытаемся вставить k-тое ребро. Если оно не пересекается с ранее вставленными, то выполняем шаг 4. 2, иначе шаг 4. 1 при k=k+1. 4. 2. Ребро вставляется в триангуляцию и вычисляется текущая суммарная длина ребер S=S+sk, где sk – длина вставляемого ребра. Если S < Smax и k < M , то выполняется шаг 4. 3, если S < Smax и k=M , то выполняется шаг 4. 4. 4. 3. Рекурсивно выполняется шаг 4. 1 при k=k+1. Затем полагается k=k− 1, S=S−sk и выполняется возврат к точке вызова данного шага. 4. 4. Запоминается текущая найденная триангуляция, полагается Smax=S и выполняется возврат к точке вызова данного шага. 5. Найденная триангуляция, дающая Smax=S , принимается за искомую, и работа алгоритма завершается

Точка в многоугольнике Один из стандартных методов определения принадлежности точки произвольному простому многоугольнику заключается Точка в многоугольнике Один из стандартных методов определения принадлежности точки произвольному простому многоугольнику заключается в следующем. Выпустим луч из данной точки в произвольном направлении (например в положительном направлении горизонтальной оси), и посчитаем сколько раз луч пересекает рёбра многоугольника. Для этого достаточно пройтись в цикле по рёбрам многоугольника и определить, пересекает ли луч каждое ребро. Если число пересечений нечётно, то объявляется, что точка лежит внутри многоугольника, если чётно — то снаружи. Это основано на том простом наблюдении, что при движении по лучу с каждым пересечением границы точка попеременно оказывается то внутри, то снаружи многоугольника. В алгоритме возникает затруднение в вырожденном случае, когда луч пересекает вершину многоугольника. Один из приёмов для его преодоления заключается в том, чтобы считать, что такие вершины многоугольника лежат на бесконечно малую величину выше (или ниже) прямой луча, и стало быть пересечения на самом деле и нет. Таким образом, пересечение луча с ребром засчитывается, если один из концов ребра лежит строго ниже луча, а другой конец — выше или лежит на луче. Алгоритм работает за время O(N) для N-угольника.

Расстояние между двумя точками Расстояние между двумя точками