Ответ 1
Так как созданный многоугольник имеет только ориентированные по оси края, вы можете рассчитать общую площадь от вертикальных плит.
Скажем, нам дан список вершин V
. Я предполагаю, что у нас есть упаковка в этом списке, поэтому мы можем запросить V.next(v)
для каждой вершины v in V
. Для последнего результат - первый.
Сначала попробуйте найти самую левую и самую правую точку и вершину, где достигается самая левая точка (в линейном времени).
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)
Теперь мы создаем простую структуру данных: для каждой вертикальной плиты мы сохраняем максимальную кучу (отсортированный список тоже хорош, но нам нужно только повторить выбор максимального элемента в конце).
width = xMax - xMin
heaps = new MaxHeap[width]
Теперь мы начинаем трассировку фигуры из вершины leftVertex
(крайняя левая вершина, найденная на первом шаге). Выберем теперь, что эта вершина имеет x/y-позицию (0, 0), просто потому, что она удобна.
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
Вы можете построить эту структуру в O(n log n)
времени, потому что добавление в кучу логарифмического времени затрат.
Наконец, нам нужно вычислить область из кучи. Для корректного ввода нам нужно получить два смежных y-значения из кучи и вычесть их.
area = 0
foreach heap in heaps
while heap not empty
area = heap.PopMax() - heap.PopMax()
return area
Снова это занимает время O(n log n)
.
Я поместил алгоритм в реализацию Java (см. Ideone). Два прогона пробега:
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));
}
Возвращает (как и ожидалось):
3
2