Ponieważ tworzony wielokąt ma tylko krawędzie wyrównane względem osi, można obliczyć całkowity obszar z pionowych płyt.
Załóżmy, że dostaliśmy listę wierzchołków V
. Zakładam, że mamy zawijanie na tej liście, więc możemy wysłać zapytanie V.next(v)
dla każdego wierzchołka v in V
. Dla ostatniego wynik jest pierwszy.
Najpierw spróbuj znaleźć lewy i prawy punkt oraz wierzchołek, w którym znajduje się lewy skrajny punkt (w czasie liniowym).
x = 0 // current x-position
xMin = inf, xMax = -inf // leftmost and rightmost point
leftVertex = null // leftmost vertex
foreach v in V
x = x + (v is left ? -1 : v is right ? 1 : 0)
xMax = max(x, xMax)
if x < xMin
xMin = x
leftVertex = V.next(v)
Teraz możemy stworzyć prostą strukturę danych: dla każdej pionowej płyty trzymamy sterty max (lista posortowana jest w porządku, jak również, ale musimy tylko powtarzalnie przynieść maksymalny element w końcu).
width = xMax - xMin
heaps = new MaxHeap[width]
Zaczynamy śledzenie kształt z wierzchołkiem leftVertex
NOW (skrajny lewy wierzchołek znaleźliśmy w pierwszym etapie). Teraz wybieramy, że ten wierzchołek ma pozycję x/y (0, 0), tylko dlatego, że jest wygodny.
x = 0, y = 0
v = leftVertex
do
if v is left
x = x-1 // use left endpoint for index
heaps[x].Add(y) // first dec, then store
if v is right
heaps[x].Add(y) // use left endpoint for index
x = x+1 // first store, then inc
if v is up
y = y+1
if v is down
y = y-1
v = V.next(v)
until v = leftVertex
Można zbudować tę strukturę w O(n log n)
czasie, ponieważ dodanie do kosztów kupa czasu logarytmicznej.
Wreszcie, musimy obliczyć obszar ze sterty. Aby uzyskać dobrze uformowane dane wejściowe, musimy pobrać dwie sąsiadujące wartości y ze sterty i odjąć je.
area = 0
foreach heap in heaps
while heap not empty
area = heap.PopMax() - heap.PopMax()
return area
Ponownie, zajmuje to godzinę O(n log n)
.
Przeportowałem algorytm do implementacji java (patrz Ideone). Dwa przykładowe przebiegi:
public static void main (String[] args) {
// _
// | |_
// |_ _ |
Direction[] input = { Direction.Up, Direction.Up,
Direction.Right, Direction.Down,
Direction.Right, Direction.Down,
Direction.Left, Direction.Left };
System.out.println(computeArea(input));
// _
// |_|_
// |_|
Direction[] input2 = { Direction.Up, Direction.Right,
Direction.Down, Direction.Down,
Direction.Right, Direction.Up,
Direction.Left, Direction.Left };
System.out.println(computeArea(input2));
}
Returns (zgodnie z oczekiwaniami):
3
2
Może po prostu skorzystaj z [wzoru geodety] (http://en.wikipedia.org/wiki/Shoelace_formula), jak sugerują inni w odpowiedziach. W twoim przypadku może być prostszy i skuteczniejszy sposób, ale .. formuła geodeta jest tutaj również dobra. – average
Czy te linie mogą się przecinać? –
@PhamTrung Załóżmy, że nie przecinają się – Vic