Сортировка книг

21

Когда вы складываете книги, вы обычно хотите, чтобы самые большие были внизу, а самые маленькие - вверху. Однако, мое скрытое ОКР заставляет меня чувствовать себя неловко, если у меня есть две книги, одна из которых короче (по высоте), но шире другой. Независимо от того, в каком порядке я их размещаю, верхняя книга будет выходить за нижнюю книгу с одной стороны.

В качестве примера, скажем, одна книга имеет размеры, (10,15)а другая имеет размеры (11,14). Независимо от того, какой путь я поставлю, я получаю навес. Но если у меня есть книги с размерами (4,3)и (5,6), я могу избежать нависания, поместив последний ниже первого.

Для целей этой задачи мы рассмотрим свесы только в отношении книги, приведенной ниже . Например , если у меня есть стек (5,5), (3,3), (4,4)(не то, что любой нормальный человек будет делать это), то верхняя книга считается как козырьком, хотя и не выходит за пределы нижней книги. Точно так же, стек (3,3), (3,3), (4,4)также имеет только один выступ, несмотря на верхних книги , выходящих за пределами нижней.

Соревнование

По заданному списку целочисленных пар для размеров книг отсортируйте эти пары / книги таким образом, чтобы количество выступов было минимальным. Вы не должны вращать книги - я хочу, чтобы все шипы стояли в одном направлении. Если существует несколько решений с одинаковым количеством свесов, вы можете выбрать любой такой порядок. Ваш алгоритм сортировки не должен быть стабильным. Ваша реализация может предполагать, что размеры книги меньше 2 16 каждый.

Временная сложность. Чтобы сделать это немного интереснее, асимптотическая сложность алгоритма в худшем случае должна быть полиномиальной по размеру стека. Таким образом, вы не можете просто проверить каждую возможную перестановку. Пожалуйста, включите краткое доказательство оптимальности и сложности вашего алгоритма и, возможно, график, который показывает масштабирование для больших случайных входов. Конечно, вы не можете использовать максимальный размер ввода в качестве аргумента, который ваш код запускает в O (1).

Вы можете написать программу или функцию, получить ввод через STDIN, ARGV или аргумент функции в любом удобном (не предварительно обработанном) формате списка и либо распечатать, либо вернуть результат.

Это код гольф, поэтому самый короткий ответ (в байтах) выигрывает.

Я уверен, что существует полиномиальное решение, но если вы можете доказать, что я неправ, вы можете представить такое доказательство вместо представления в гольф. В этом случае вы можете предположить, что P ≠ NP . Я приму первое правильное доказательство и вознаградлю его за это.

Примеры

In:  [[1, 1], [10, 10], [4, 5], [7, 5], [7, 7], [10, 10], [9, 8], [7, 5], [7, 5], [3, 1]]
Out: [[10, 10], [10, 10], [9, 8], [7, 7], [7, 5], [7, 5], [7, 5], [4, 5], [3, 1], [1, 1]]

In:  [[4, 5], [5, 4], [5, 4], [5, 4], [5, 4], [4, 5], [4, 5], [4, 5], [5, 4], [4, 5]]
Out: [[4, 5], [4, 5], [4, 5], [4, 5], [4, 5], [5, 4], [5, 4], [5, 4], [5, 4], [5, 4]]
  or [[5, 4], [5, 4], [5, 4], [5, 4], [5, 4], [4, 5], [4, 5], [4, 5], [4, 5], [4, 5]]

In:  [[2, 3], [1, 1], [5, 5], [7, 1]]
Out: [[5, 5], [2, 3], [7, 1], [1, 1]]
 or  [[5, 5], [2, 3], [1, 1], [7, 1]]
 or  [[7, 1], [5, 5], [2, 3], [1, 1]]
 or  [[7, 1], [1, 1], [5, 5], [2, 3]]

Я создал их вручную, поэтому дайте мне знать, если вы заметите какие-либо ошибки.

Мартин Эндер
источник
3
Вы уверены, что нахождение решения с минимальным количеством свесов может быть решено за полиномиальное время?
COTO
@COTO Я довольно уверен, да.
Мартин Эндер
Хм. Я бы обычно решал его с помощью жадного алгоритма, но я легко могу получить входные данные, приводящие к неоптимальным выходным данным для любого критерия «жадности», который я могу придумать (например, площадь, максимизировать одно измерение, максимизировать наименьшее измерение и т. Д.). Единственные другие подходы, которые я могу придумать, включают разделение книг на клики, и все они имеют экспоненциальную сложность в худшем случае. Мне будет интересно посмотреть, какие ответы придут. Вы также можете запросить краткое доказательство оптимальности сортировки как часть спецификации.
КОТО
@COTO Я добавил параграф об этом на случай, если я действительно неправ, но не рассчитывайте на это. ;)
Мартин Эндер
На всякий случай, потенциальные доказательства того, что не существует алгоритма полиномиального времени, должны позволять предполагать, что P не равно NP.
xnor

Ответы:

2

Пиф , 30

FN_SQFbYIgeeYeb~b]NB)E~Y]]N;sY

Это прямой гольф потрясающего алгоритма GRC. Вот точный эквивалент вышеупомянутой программы pyth в ее скомпилированном коде python.

Q = eval(input())
Y = []
for N in sorted(Q)[::-1]:
     for b in Y:
         if Y[-1][-1] >= b[-1]:
             b += [N]
             break
     else:
         Y += [[N]]
print(Psum(Y))

В этом контексте Psum(Y)функция эквивалентна питону sum(Y,[]).

Фактический скомпилированный и запущенный код (из pyth -d):

Y=[]
Q=copy(eval(input()))
for N in neg(Psorted(Q)):
 for b in Y:
  if gte(end(end(Y)),end(b)):
   b+=[N]
   break
 else:
  Y+=[[N]]
Pprint("\n",Psum(Y))
isaacg
источник
1
Перевод Python требует "Y = []", удалите eval, если вы находитесь в Python 2, а сумма нуждается во втором аргументе sum(Y,[]). Все это должно работать в Pyth, просто перевод не включает его автоматически.
xnor
@xnor Последняя строка действительно гласит: Pprint("\n",Psum(Y)). Я думаю, что он, возможно, упростил это для удобства, наряду со всеми -1s и т. Д. На Psumсамом деле будет работать больше как reduce(lambda x,y:x+y, Y[1:], Y[0]).
FryAmTheEggman
20

Python, 113

P=[]
for n in sorted(input())[::-1]:
 for p in P:
  if p[-1][1]>=n[1]:p+=[n];break
 else:P+=[[n]]
print sum(P,[])

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

Я не очень хорошо справляюсь со сложностью времени, но я считаю, что это будет наихудший случай O ( N 2 ). Есть два цикла , каждый из которых имеет не более N итераций. Я также использую встроенную сортировку Python, которая является O ( n log n ).


Мое первое доказательство того, что этот алгоритм дает оптимальные решения, оказалось неверным. Огромное спасибо @xnor и @ Sp3000 за отличную дискуссию в чате о том, как это доказать (которую вы можете прочитать, начиная здесь ). Разработав правильное доказательство, @xnor обнаружил, что часть его уже была сделана ( теорема Дилворта ).

В любом случае, вот обзор доказательства (спасибо @xnor и @ Sp3000).

Во-первых, мы определяем понятие antipile, или antihain ( цитата из @xnor ):

Антипила - это последовательность книг уменьшающейся высоты, но увеличивающейся ширины.
Таким образом, каждая последующая книга строго выше, но строго меньше.
Обратите внимание, что любая книга в антипиле нависает над любой другой книгой в антипиле.
Таким образом, в антипиле нет двух книг. быть в той же куче.
Как следствие, если вы можете найти антипилу х книг, то эти книги должны быть в разных стопках.
Таким образом, размер самой большой антипилы является нижней границей количества стопок.

Затем мы сортируем книги в порядке убывания по их ширине (первая) и их высоте (вторая) *.

Для каждой книги B мы делаем следующее:

  1. Если B может поместиться в первую кучу, мы помещаем ее туда и продолжаем.
  2. В противном случае мы найдем самую раннюю * кучу х, которая B может быть помещен. Это может быть новая куча, если это необходимо.
  3. Далее мы связываем B с P , где P - верхняя книга на предыдущей стопке x - 1 .
  4. Теперь мы знаем, что:
    • B строго * меньше ширины, чем P , так как книги сортируются по убыванию по ширине
    • B строго больше по высоте, чем P , иначе мы бы поместили B поверх P

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

Отличная диаграмма @ Sp3000 хорошо иллюстрирует это:

Следуя по любому пути от последней кучи (справа) до первой кучи (слева), мы получаем антипиле. Важно отметить, что длина этой стопки равна количеству стопок. Следовательно, количество используемых свай минимально.

Наконец, поскольку мы организовали книги в минимальное количество стопок без перекрытий, мы можем сложить их друг на друга, чтобы получить одну стопку с минимальным количеством перекрытий.

* этот полезный комментарий объясняет несколько вещей

GRC
источник
3
+1 за показательное доказательство и ссылку на обсуждение. Реквизит xnor et al.
COTO
Я должен уточнить, что теорема Дилворта не охватывает всего доказательства, а только тот факт, что наименьшее количество стопок равно антипиле наибольшего размера.
xnor