Материал: 252_337

Внимание! Если размещение файла нарушает Ваши авторские права, то обязательно сообщите нам

I inc(i)

{Перехід до наступної вершини багатокутника.}

until flag or (і = n);

 

if flag or Odd(count) {Точка належить багатокутнику, коли вона збігається з однією}

then writeln(f_OUt, 'Yes') {із вершин або кількість перетинів ребер непарна.}

else writeln(f_out,'No');

Оскільки для визначення положення точки відносно задано­ го n-кутника необхідно порахувати кількість перетинів побудо­ ваного горизонтального відрізка з його сторонами, то оцінка ефективності роботи такого алгоритму буде лінійною і станови­ тиме О(га).

Для тестування алгоритму необхідно переглянути всі мож­ ливі випадки розташування точки на площині відносно задано­ го своїми вершинами n-кутника: точка усередині багатокутни­ ка; точка ззовні багатокутника, але побудований відрізок прямої перетинає багатокутник; точка ззовні багатокутника і відрізок не перетинає його.

Щодо вигляду самого багатокутника, то обов'язковим є не тільки задання багатокутників як з невеликою кількістю вер­ шин, наприклад до 10, так і з достатньо великою, наприклад близько 100.

Другою характерною особливістю є задання таких багатокут­ ників, у яких відбувається перетин вершин, дотик до вершин при перетині, належність заданої точки стороні багатокутника або одній із його вершин. При цьому потрібно розглядати як опуклі, так і неопуклі багатокутники.

Для отримання максимальної результативності виконання тестування побудованого алгоритму щодо визначення розмі­ щення точки відносно заданого багатокутника всі зазначені вище параметри рекомендується комбінувати у різноманітних варіантах.

Побудова опуклої оболонки

Під опуклою оболонкою розу­ міють опуклий багатокутник міні­ мальної площі, який містить у собі всі задані точки на площині. Зро­ зуміло, що вершинами такого ба­ гатокутника можуть бути лише де­ які точки із множини заданих, а всі решта заданих точок лежатимуть у середині побудованого багатокут­ ника (мал. 152).

Побудову опуклої оболонки можна наочно уявити собі наступним чином. Нехай на плоску дошку, що відіграє роль площини, набито багато цвяхів, що є заданими точками. Наки­ немо на цвяхи мотузку таким чином, щоб усі їх охопити, і поч-

267

немо її стягувати, зав'язуючи у вузол. Врешті-решт наша мо­ тузка охопить усі цвяхи, зачепившись за деякі з них, і утво­ рить опуклу оболонку.

Ознакою опуклого багатокутника є те, що коли через будьяку з його сторін провести пряму, то весь багатокутник лежа­ тиме в одній півплощині.

Відповідно до цієї ознаки можна запропонувати алгоритм побудови опуклої оболонки, який базується на найпростіших міркуваннях. Для цього на першому кроці визначимо точку з найменшим значенням по осі абсцис, яка обов'язково входить до опуклої оболонки. Далі з цією точкою і рештою точок за­ даної множини утворимо пари, проведемо через них прямі і перевірятимемо, чи лежать усі інші точки по один бік від по­ точної прямої. Якщо така пара буде знайдена, то нова точка включається до послідовності вершин опуклої оболонки і, від­ повідно, виключається із наступного перегляду. Далі для цієї точки шукається наступна пара.

Це далеко не кращий алгоритм щодо часу його виконання. Його можна визначити як повноперебірний. Оцінку ефектив­ ності цього алгоритму можна визначити так. На кроці побудо­ ви прямих для визначених пар точок оцінка ефективності ста­ новить 0(п2). Однак для кожної такої прямої необхідно пере­ глянути решту точок для визначення їхнього розміщення на площині відносно цієї прямої, що становить 0(гі). Таким чи­ ном, загальна оцінка запропонованого алгоритму буде 0(п3).

Далі розглянемо більш ефективні методи розв'язання побу­ дови опуклої оболонки.

Метод додавання точок

Ідея методу полягає в тому, що, коли обходити побудовану опуклу оболонку, наприклад, за годинниковою стрілкою, на­ прям повороту завжди буде однаковим. Визначення напряму повороту досягається аналізом координат трьох сусідніх вер­ шин опуклої оболонки.

 

Розглянемо фрагмент побудови

 

деякої опуклої оболонки для 4-х то­

 

чок (мал. 153). Зручно розглядати

А ..

ці точки у певній послідовності.

Р*

Зрозуміло, що крайня зліва точка,

Мал 153

Щ0 м а є найменше значення по осі

 

абсцис, увійде до опуклої оболонки.

Саме тому почнемо перегляд з неї. Далі розглядатимемо точки у порядку зростання значень їх абсцис. Саме за цією ознакою на малюнку 153 визначена послідовність точок р^,р2^Р^Рі'

Якщо переглядати точки згідно з послідовністю їх задання, то спочатку будуть з'єднані точки р1 ір2, потім р2 ір3, і наоста-

268

нокрд» РІ- Отримана ламана не буде опуклою оболонкою, у ній зайвими є два відрізки, позначені на малюнку 153 пунктиром. Вірною побудовою буде з'єднання відрізками точок рх, р3, р4 . Як визначити коректність побудови цієї ламаної? Із точки р1 спостерігатимемо за переміщенням із точки р2 у точку р3. При цьому буде виконано лівий поворот, тобто поворот проти годин­ никової стрілки. Запам'ятаємо цей факт.

Далі перейдемо у точку р2 і з неї спостерігатимемо за пе­ реміщенням із точки р3 у точку р4. Тепер буде здійснено правий поворот, тобто поворот за годинниковою стрілкою. Отже, пору­ шена ознака незмінного повороту при обході опуклою оболон­ кою: оскільки ми виконуємо обхід за годинниковою стрілкою, то повинні весь час робити правий поворот. Якщо вилучити із перегляду точку р2, то, спостерігаючи із точкир1 за переміщен­ ням із точки р3 У точку j?4, зафіксуємо правий поворот.

Розглянемо технічні моменти запропонованого алгоритму, а саме як формувати послідовність точок, що утворюють опуклу оболонку, та як вилучати із неї ті точки, які виявилися зайвими.

Найпростіше усі точки поточного стану опуклої оболонки запи­ сувати у стек. Першим елементом стеку завжди буде точкар1 упо­ рядкованої послідовності всіх заданих точок. На і-му кроці з точ­ ки рі дивитимемося у точки рі+1 і рі+2. Якщо матиме місце вираз

(Рі+і ~ РІ) * (Р/+2 - Рд = (ХІ+І - ХІЩ+І - У І) ~ (ХІ+2 - *ЩІг ~ У І) % °» т о

це означатиме, що виконано правий поворот проти годинни­ кової стрілки і точка рі + 1є претендентом на вершину опуклої оболонки та повинна бути занесена до вершини стеку.

А як бути у протилежному ви­ падку, якщо точка рі+1 до стеку не заноситься? Розглянемо малюнок 154. На перших двох кроках у стек буде занесено точки рх, р2, р3. Для точки р4 умова належності опуклій оболонці не виконується, і вона не потрапляє до стеку.

Але з малюнка 154 видно, що і точки р2, р3 також необхідно виключити. Для цього треба

дослідити верхній елемент стеку, у нашому випадку це точкар3 . Якщо і для пари точок р3 ірь не виконується необхідна умова, то стек зменшується на один елемент шляхом виключення з нього точки, що знаходиться у його вершині, тобто р3. Така послідовність дій продовжується до тих пір, поки не знайдеться у вершині стеку точка, для якої разом із точкою рь необхідна умова виконається. Тоді точка р5 занесеться у стек і для нашого прикладу поточний вміст стеку буде таким: pvp5. До речі, відки­ нуті точки р2, р3, р4 будуть брати участь у наступному перегляді, коли будуватиметься нижня частина опуклої оболонки.

269

Наскільки ефективним є даний алгоритм? Найперше по­ мітне те, що при побудові опуклої оболонки всі точки розгляда­ ються максимум двічі: перший раз, коли будується верхня час­ тина опуклої оболонки, а другий раз - нижня. По-друге, для визначення напряму повороту виконується мінімальна кількість арифметичних операцій.

Однак і цю кількість дій можна зменшити, покращивши ефективність алгоритму. Логіка міркувань є такою. Якщо відо­ ма найлівіша точка, що належить опуклій оболонці, то так са­ мо можна визначити і найправішу, тобто ту, у якої найбільше значення по осі абсцис. Якщо через ці дві точки провести пря­ му, то вся множина заданих точок на площині буде розбита на дві під множини. Ті точки, що лежатимуть нижче від побудова­ ної прямої, аж ніяк не можуть бути претендентами на вершини опуклої оболонки у її верхній частині.

Те саме можна сказати і про точки, що лежать вище від пря­ мої: серед них не варто шукати вершини нижньої частини опуклої оболонки. Таким чином, усі точки, які не лежать на побудованій прямій, а вони можуть належати як верхній, так і нижній частині опуклої оболонки, братимуть участь у пере­ гляді лише один раз.

Таким чином, застосувавши розбиття заданої множини то­ чок на дві підмножини, використавши для цього побудову пря­ мої, що проходить через крайні горизонтальні точки, можна значно скоротити кількість переглядів усіх заданих точок при побудові опуклої оболонки. Це дає змогу говорити про часткове застосування методу «розділяй і володарюй».

Варто звернути увагу ще на таке питання: а якщо серед заданих то­ чок виявиться кілька таких, що мають найменше значення по осі абсцис? Яку з них визначати як по­ чаткову? Мабуть, це не має вирі­ шального значення, оскільки на­ віть при розбитті множини точок на дві підмножини ми у гіршому

випадку матимемо одну під множину точок порожню, а до дру­ гої будуть віднесені решта точок (мал. 155). Але й у цьому разі всі точки переглядатимуться лише по одному разу.

Таким чином, можна сформулювати основні етапи алгорит­ му побудови опуклої оболонки методом додавання точок.

1.Упорядкувати всі задані точки за зростанням значень їх абсцис х., зберігши у масиві mast їх початкову нумерацію.

2.Розбити всі точки з номерами від mas2 до masn_1 на дві підмножини, визначивши цей факт перевіркою умови: якщо

(Хі ~ Хта8)(Утаа„ ~ У mas) " U/l ~ Утае)(Хтав„ " Xmas) < 0, ДЄ і = maS2,

270

mas3, ..., masn_x, то такі точки належать до однієї підмножини, у протилежному випадку - до іншої. Відповідні підмножини можуть утворювати два масиви з номерами вершин у порядку зростання їх абсцис. Одночасно необхідно дізнатися, яка з підмножин точок знаходиться над прямою, а яка - під нею. Для цього треба визначити, у яку підмножину потрапить точка з максимальним значенням ординати. Саме з цієї підмножини точок починається побудова опуклої оболонки.

3.Занести у стек порядковий номер першої точки верхньої упорядкованої під послідовності, що відповідає верхній під мно­ жині точок.

4.Якщо не досягнуто останньої точки верхньої підмножини точок, то визначити напрям повороту для наступних двох то­ чок цієї під послідовності. У протилежному випадку перейти до п. 7.

5.Якщо поворот правий, то занести номер нової точки опук­ лої оболонки до стеку і перейти до п. 4.

6.У протилежному випадку зменшити значення вершини стеку на 1 і перейти до п. 4.

7.Завершити побудову верхньої частини опуклої оболонки і перейти до побудови нижньої, розглянувши п. 3-7 для другої під послідовності, врахувавши, що підпослідовність нижніх то­ чок розглядається з кінця до початку.

Наведемо фрагмент основної частини програми, що реалізує описаний алгоритм.

SOrt(1, п);

{Упорядкування точок за зростанням значень абсцис.}

w := 1; V := 1;

{Розбиття множини точок на дві підмножини.}

Р 1 [ 1 ] : = р [ 1 ] ; р 2 [ 1 ] : = р [ 1 ] ; х1[1]:=х[1];х2[1]:=х[1];

у1[1]:=у[1];у2[1]:=у[1]; for і := 2 to п - 1 do

begin

if (х[і] - х[1]) * (у[п] - у[1]) - (у[і] - у[1]) * (х[Щ - х[1]) <= 0 then begin inc(w); p1[w] := p[i]; x1[w] :=x[i]; y1[w] :=y[i] end else begin inc(v); p2[v] := p[i]; x2[v] := x[i]; y2[v] := y[i] end;

end;

 

inc(w); inc(v);

{Дописування до двох множин крайньої справа точки.}

р1 [w] := p[n]; х1 [w] := x[n]; у1 [w] := у[п]; p2[v] := p[n]; x2[v] := x[n]; y2[v] := у[п];

Х_0

:= х[1]; у_0 := у[1];

{Обчислення параметрів для визначення}

х_1

:= х1 [2]; у_1 := у1 [2];

{«верхньої» і «нижньої» підмножини.}

х_2:=х2[2];у_2:=у2[2];

 

 

{Визначення положення підмножин відносно прямої,}

 

 

{що проходить через крайні ліву і праву точки.}

if (х_1 - х_0) * (у_2 - у_0) - (х_2 - х_0) * (у_1 - у_0) <= 0

then for і := 1 to (v div 2) do

{Упорядкування за спаданням точок,}

271

Источник: https://studfile.net/preview/14502490/