Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Разработка эффективных алгоритмов.doc
Скачиваний:
118
Добавлен:
24.11.2019
Размер:
1.2 Mб
Скачать

7 .3. Задача о выпуклой оболочке

На плоскости задано множество S, состоящее из N точек. Требуется построить выпуклую оболочку, то есть определить точки, соединяя которые линиями, мы получаем охватывающий выпуклый контур.

7.3.1. Алгоритм Грэхема

Т ройки последовательно идущих точек проверяются в порядке обхода против часовой стрелки. Если обход выполняется против часовой стрелки, то точки образуют левый поворот, если по часовой стрелке, то правый поворот. Так, например, для точек на рис.7.6 левый поворот образован точками (1,2,3), (2,3,4), (4,5,1), а правый – (3,4,5).

Основная идея алгоритма Грэхема:

  1. найти внутреннюю точку t;

  2. используя t как начало координат, отсортировать точки множества S по неубыванию в соответствии с полярным углом и расстоянием от t;

  3. выполнить обход точек, исключая точки, образующие правый поворот.

Эту идею можно упростить – найти не внутреннюю точку, а самую левую верхнюю. Она заведомо принадлежит выпуклой оболочке. При этом значения углов вычисляются относительно этой точки.

Фрагменты алгоритма.

Grehеm (N, A, M)

// N – число точек

// A(N) array of Point – массив точек (координаты)

// M – количество точек в выпуклой оболочке

// Ls(N) – номера точек (при инициализации ls[i]=i)

// bb(N) – логический признак принадлежности точки выпуклой оболочке

// Rd(N) – оценки полярных углов

// 1 этап – поиск самой левой верхней точки

j1

for i=2 to N do

if (A[j].x>A[i].x) OR (A[i].x=A[j].x AND A[i].y>A[j].y)

then j=i

endif

endfor

// делаем крайнюю левую точкой первой

Swap (A[1], A[j])

Swap (Ls[1], Ls[j])

// на первом месте стоит левая верхняя точка

// далее определяем синусы углов. Углы принадлежат первой и четвер- // той четверти. Если углы задать в диапазоне [-90, 90] и отсортиро- // вать в порядке неубывания, то выпуклую оболочку можно построить // обходом против часовой стрелки

for i=2 to N do

dxA[i].x-A[1].x; dyA[i].y-A[1].y

Rd[i]dy/Sqrt(dx^2+dy^2)

еndfor

// далее некоторой сортировкой упорядочиваем углы. Только необходи- // мо не забывать одновременно с перестановкой ключа Rd[i] перестав- // лять и соответствующие элементы в массивах Ls и А

Sort(Rd, N)

// если число точек больше 3, то выполняем обход точек в поисках // выпуклой оболочки

If N>3 then Rounds

endif

end

//Процедура обхода точек

Procedure Rounds

MN // количество точек в выпуклой оболочке

LfA[1]; mdA[2]; rgA[3] // выбираем 3 точки обхода

Lfi1; mdi2; rgi3; // запоминаем индексы точек

While rgi<> 1 do

// определяем ориентированную площадь

RSorient(lf, md, rg)

If R<0 then // исключаем точку с номером mdi из выпуклой оболочки

Bb[mdi]false; M=M-1; mdirgi; mdrg; rgirgi mod N +1; rgA[rgi]

Else // переходим к следующей точке, если ориентация // нормальная

Lfimdi; lfmd; mdirgi; mdrg;

Rgirgi mod N+1; rgA[rgi]

еndif

еndwhile

еnd