Как эффективно спаривать носки из кучи?

вчера я спаривал носки из чистой прачечной и выяснил, как я это делал, не очень эффективно. Я делал наивный поиск-выбирал один носок и" перебирал " кучу, чтобы найти его пару. Это требует итерации по n/2 * n / 4 = n2/8 носков в среднем.

как ученый, я думал, что я мог сделать? Сортировка (по размеру/цвету/...) конечно, пришло в голову достичь O(NlogN) решение.

хэширование или другие решения не на месте не являются вариантом, потому что я не могу дублировать свои носки (хотя было бы неплохо, если бы я мог).

Итак, вопрос по существу:

учитывая кучу n пары носков, содержащие 2n элементы (предположим, что каждый носок имеет ровно одну подходящую пару), каков наилучший способ эффективно соединить их с логарифмическим дополнительным пространством? (Я думаю, что могу вспомнить это количество информация при необходимости.)

Я буду признателен за ответ, который касается следующих аспектов:

  • общие теоретической решения для огромного количества носков.
  • фактическое количество носков не так велико, я не верю, что у моего супруга и у меня есть более 30 пар. (И довольно легко отличить мои носки от ее; можно ли использовать и это?)
  • это эквивалентно отчетливостью элемент проблема?

30 ответов


были предложены решения для сортировки, но сортировка немного слишком много: нам не нужен порядок; нам просто нужны группы равенства.

так хеширования было бы достаточно (и быстрее).

  1. для каждого цвета носков, форма куче. Повторите все носки в корзине ввода и распределить их на цветные стопки.
  2. повторите каждую кучу и распространять его с какая-то другая метрика (например, шаблон) во второй набор свай
  3. рекурсивно применить эту схему пока вы не раздали все носки на очень маленькие сваи, которые вы можете визуально обрабатывать немедленно

этот вид рекурсивного хэш-разбиения фактически выполняется SQL Server когда ему нужно хэш-соединение или хэш-агрегат над огромными наборами данных. Он распределяет свой входной поток сборки на многие разделы, которые являются независимыми. Эта схема масштабируется до произвольных объемов данных и нескольких процессоров линейно.

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

если бы каждый носок имел целое число под названием "PairID", можно было бы легко распределить их на 10 ведер в соответствии к PairID % 10 (последняя цифра).

лучшее реальное разделение, которое я могу придумать, - это создание прямоугольник шпунты: одно измерение-цвет, другое-шаблон. Почему прямоугольник? Потому что нам нужен O (1) произвольный доступ к сваям. (В 3D кубовидная также будет работать, но это не очень практично.)


обновление:

насчет параллельность? Может ли несколько человек соответствовать носкам быстрее?

  1. самая простая стратегия распараллеливания состоит в том, чтобы несколько работников взяли из входной корзины и положили носки на сваи. Это только масштабируется так много - представьте, что 100 человек сражаются за 10 свай. стоимость синхронизации (проявляя себя как столкновения рук и человеческое общение) уничтожить эффективность и ускорение (см. Универсальный Закон Масштабируемости!). Это склонно к взаимоблокировок? Нет, потому что каждому работнику нужен доступ только к одной куче за раз. Только с одним "замком" не может быть тупика. Livelocks может быть возможно в зависимости от того, как люди координируют доступ к сваи. Они могут просто использовать случайных переключений как сетевые карты делают это на физическом уровне, чтобы определить, какая карта может исключительно получить доступ к сетевому проводу. Если это работает для Никс, это должно работать и для людей.
  2. он масштабируется почти бесконечно если каждый работник имеет свой собственный набор стопок. Затем рабочие могут взять большие куски носков из входной корзины (очень мало споров, поскольку они делают это редко), и им не нужно синхронизировать при распределении носков вообще (потому что у них есть локальные сваи). В конце концов, все рабочие должны объединить свои наборы свай. Я считаю, что это можно сделать в O (log (worker count * per worker)), если рабочие образуют агрегация дерево!--7-->.

насчет проблема различимости элементов? Как говорится в статье, Проблема различимости элементов может быть решена в O(N). Это то же самое для Проблемы с носками (также O(N), Если вам нужен только один шаг распределения (я предложил несколько шагов только потому, что люди плохи в расчетах - одного шага достаточно, если вы распространяете на md5(color, length, pattern, ...), то есть a идеальный хэш всех атрибутов)).

ясно, что нельзя идите быстрее, чем O(N), Итак, мы достигли оптимальная нижняя граница.

хотя выходы не совсем одинаковы (в одном случае, просто логическое значение. В другом случае пары носков), асимптотические сложности одинаковы.


поскольку архитектура человеческого мозга полностью отличается от современного процессора, этот вопрос не имеет практического смысла.

люди могут выиграть алгоритмы CPU, используя тот факт, что" поиск совпадающей пары " может быть одной операцией для набора, который не слишком велик.

мой алгоритм:

spread_all_socks_on_flat_surface();
while (socks_left_on_a_surface()) {
     // Thanks to human visual SIMD, this is one, quick operation.
     pair = notice_any_matching_pair();
     remove_socks_pair_from_surface(pair);
}

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


корпус 1: все носки одинаковые (это то, что я делаю в реальной жизни, кстати).

выбрать любые два из них, чтобы сделать пару. Постоянное время.

корпус 2: существует постоянное количество комбинаций (владение, цвет, размер, текстура и т. д.).

использовать radix sort. Это только линейное время, так как сравнение не требуется.

корпус 3: количество комбинаций не известно в аванс (общий случай).

мы должны сделать сравнение, чтобы проверить, приходят ли два носка в паре. Выберите один из O(n log n) алгоритмы сортировки на основе сравнения.

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


не алгоритмический ответ, но "эффективный", когда я это делаю:

  • Шаг 1) отбросьте все существующие носки

  • Шаг 2) Перейти к Walmart и покупают их пакетами 10-N пакетов белый и m пакетов черного. Нет необходимости в других цветах в повседневной жизни. жизнь.

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

алгоритмическом ответ:

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

  • поэтому возьмите пять из них наугад и запомните их форму или их длину.

почему пять? Обычно люди хорошо запоминают между пятью и семью различными элементами в рабочей памяти - немного похоже на человеческий эквивалент RPN stack-five является безопасным по умолчанию.

  • Возьмите один из стека 2n-5.

  • теперь найдите совпадение (визуальное сопоставление шаблонов-люди хороши в этом с небольшим стеком) внутри пяти, которые вы нарисовали, если вы не найдете одного, добавьте это к своим пяти.

  • сохранить случайным образом выбирая носки из стека и сравнить с 5 + 1 Носки для матча. По мере роста вашего стека это уменьшит вашу производительность, но повысит ваши шансы. Гораздо быстрее.

Не стесняйтесь записывать формулу, чтобы рассчитать, сколько образцов вам нужно нарисовать для 50% шансов на матч. МСИО это закон гипергеометрическое.

Я делаю это каждое утро и редко нужно больше, чем три ничьи - но у меня есть n аналогичные пары (около 10, плюс-минус потерянные ) с m формы белые носки. Теперь вы можете оценить размер моей стопки акций : -)

кстати, я обнаружил, что сумма транзакционных затрат на сортировку всех носков каждый раз, когда мне нужна пара, была намного меньше, чем сделать это один раз и связать носки. Just-in-time работает лучше, потому что тогда вам не нужно связывать носки, и есть также уменьшающаяся предельная доходность (то есть вы продолжаете искать эти два или три носка, когда где-то в прачечной и что вам нужно закончить соответствие ваших носков,и вы теряете время на это).


этот подход может быть довольно легко реализован в массиве, предполагая, что "удаление" Носков является выбор. на самом деле, вам даже не нужно "снимать" носки. Если вам не нужна сортировка носков (см. Ниже), вы можете просто переместить их и получить массив, в котором все носки расположены парами в массиве.

предполагая, что единственной операцией для socks является сравнение для равенства, этот алгоритм в основном все еще n2 алгоритм, хотя я не знаю о среднем случае (никогда не учился вычислять это).

сортировка, of курс повышает эффективность, особенно в реальной жизни, где вы можете легко "вставить" носок между двумя другими носками. В вычислениях то же самое может быть достигнуто деревом, но это дополнительное пространство. И, конечно, мы вернулись в NlogN (или немного больше, если есть несколько носков, которые одинаковы по критериям сортировки, но не из одной пары).

кроме этого, я ничего не могу придумать, но этот метод кажется довольно эффективным в реальной жизни. :)


Это неправильный вопрос. Правильный вопрос: почему я трачу время на сортировку носков? Сколько это стоит на ежегодной основе, когда вы оцениваете свое свободное время для X денежных единиц по вашему выбору?

и чаще всего это не просто любой свободное время, это утро свободное время, которое вы могли бы провести в постели, или потягивая кофе, или уходя немного рано и не будучи пойманным в пробке.

Это часто хорошо сделать шаг назад и подумать, как обойти проблему.

и есть путь!

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

лучше, если нет никакой разницы между левыми и правыми носками, но это не критично. Если носки симметричны слева направо, поиск пары-это операция O(1), а сортировка носков-приблизительная операция O(M), где M-количество мест в вашем доме, которые вы завалили носками, в идеале некоторое небольшое постоянное число.

Если вы выбрали причудливую пару с разным левым и правым носком, сделав полную сортировку ведра слева и справа, ведра для ног берут O (N+M), где N-количество носки и М такие же, как и выше. Кто-то другой может дать формулу для средних итераций поиска первой пары, но худшим случаем для поиска пары со слепым поиском является N/2+1, что становится астрономически маловероятным случаем для разумного N. Это можно ускорить, используя передовые алгоритмы распознавания изображений и эвристику, при сканировании кучи несортированных носков с Мк1 Глаз.

Итак, алгоритм достижения эффективности спаривания носков O(1) (при условии симметрии носок) есть:

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

  2. вам нужно узнать, как вы можете заказать выбранный носок оптом и сколько это стоит, и они доставляют.

  3. заказать носочки!

  4. избавьтесь от своих старых носков.

альтернативный Шаг 3 будет включать сравнение затрат на покупку такого же количества, возможно, более дешевых носков по несколько пар за раз на протяжении многих лет и добавление стоимости сортировки носков, но поверьте мне на слово: покупка оптом дешевле! Кроме того, носки при хранении увеличивают стоимость при темпе инфляции цен на акции, которая больше, чем вы получили бы от многих инвестиций. Опять же, есть и стоимость хранения, но носки действительно не занимают много места на верхней полке шкафа.

решена. Итак, просто получите новые носки, выбросьте/пожертвуйте свои старые и живите счастливо, зная, что вы экономите деньги и время каждый день до конца своей жизни.

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

вы можете достичь O (n) с помощью radix сортировать. Вам просто нужно выбрать некоторые атрибуты для ведра.

  1. сначала вы можете выбрать (она, моя) - разделить их на 2 кучки,
  2. затем используйте цвета (может иметь любой порядок для цветов, например, в алфавитном порядке по имени цвета) - разделить их на кучи по цвету (не забудьте сохранить начальный заказ с шага 1 для всех носков в одной стопке),
  3. тогда длина носка,
  4. затем текстурой, ....

Если вы можете выбрать ограниченное количество атрибутов, но достаточно атрибутов, которые могут однозначно идентифицировать каждую пару, вы должны быть сделаны в O(k * n), который является O(n), если мы можем считать K ограниченным.


как практическое решение:

  1. быстро сделайте кучи легко различимых носков. (Скажем, по цвету)
  2. Quicksort каждая куча и использовать длину носка для сравнения. Как человек, вы можете принять довольно быстрое решение, какой носок использовать для разделения, что позволяет избежать худшего случая. (Вы можете видеть несколько носков параллельно, используйте это в своих интересах!)
  3. остановить сортировку свай, когда они достигли порога, на котором вам удобно найти пары пятен и unpairable носки мгновенно

если у вас есть 1000 носков, с 8 цветами и средним распределением, вы можете сделать 4 стопки каждых 125 носков за c*n время. С порогом 5 носков вы можете сортировать каждую кучу в 6 пробегов. (Подсчет 2 секунд, чтобы бросить носок на правую кучу, займет у вас немного меньше 4 часов.)

если у вас есть только 60 носков, 3 цвета и 2 вида носков (ваши / вашей жены), вы можете сортировать каждую кучу 10 носков за 1 проход (снова порог = 5). (Подсчет 2 секунд займет у вас 2 минуты).

начальная сортировка ведра ускорит ваш процесс, потому что она делит ваши носки n на K ведер в c*n время так, чем вам придется только делать c*n*log(k) работа. (Без учета порога). Так что все, что вы делаете о n*c*(1 + log(k)) работа, где c-время, чтобы бросить носок на кучу.

этот подход будет благоприятным по сравнению с любым c*x*n + O(1) способ примерно пока log(k) < x - 1.


в информатике это может быть полезно: У нас есть коллекция n вещи, приказ о них (длина), а также отношение эквивалентности (дополнительная информация, например, цвет носков). Отношение эквивалентности позволяет нам сделать разбиение исходной коллекции, и в каждом классе эквивалентности наш порядок все еще сохраняется. Отображение a вещь к его классу эквивалентности можно сделать в O (1), поэтому только O(n) необходим назначение каждого элемента классу. Теперь мы использовали нашу дополнительную информацию и можем продолжить любым способом сортировать каждый класс. Преимущество в том, что наборы данных уже значительно меньше.

метод также может быть вложенным, если у нас есть несколько отношений эквивалентности -> сделать цветные кучи, чем внутри каждой секции кучи по текстуре, чем Сортировать по длине. Любое отношение эквивалентности, которое создает раздел с более чем 2 элементами, имеющими примерно четный размер, приведет к скорости улучшение по сравнению с сортировкой (при условии, что мы можем напрямую назначить носок его куче), и сортировка может произойти очень быстро на небольших наборах данных.


этот вопрос на самом деле глубоко философский. В глубине души речь идет о том, эквивалентна ли способность людей решать проблемы ("wetware" нашего мозга) тому, что может быть достигнуто с помощью алгоритмов.

очевидный алгоритм сортировки носков:

Let N be the set of socks that are still unpaired, initially empty
for each sock s taken from the dryer
  if s matches a sock t in N
    remove t from N, bundle s and t together, and throw them in the basket
  else
    add s to N

теперь информатика в этой проблеме все о шагах

  1. "если S пар с носком t в N". Как быстро мы можем "вспомнить" то, что видели? далеко?
  2. " удалить t из N "и"добавить s в N". Сколько стоит отслеживание того, что мы видели до сих пор?

люди будут использовать различные стратегии для их осуществления. человека is ассоциативные, что-то вроде хэш-таблицы, где наборы хранящимися в паре с соответствующими значениями. Например, понятие "красный автомобиль" соответствует всем красным автомобилям, которые человек способен запомнить. Кто-то с идеальная память имеет идеальное отображение. Большинство людей несовершенны в этом отношении (и большинство других). Ассоциативная карта имеет ограниченную емкость. Mappings может цензура из существования при различных обстоятельствах (одно пиво слишком много), записывается по ошибке ("я, хотя ее звали Бетти, а не Нетти"), или никогда не перезаписывается, хотя мы наблюдаем, что правда изменилась ("папина машина" вызывает "оранжевый Жар-птица", когда мы на самом деле знали, что он обменял это на красный Camaro).

в случае носков, идеальный отзыв означает, глядя на носок s всегда производит память своего брата t, включая достаточную информацию (где она находится на гладильной доске), чтобы найти t в постоянное время. Человек с фотографической памятью выполняет как 1, так и 2 в постоянное время в обязательном порядке.

кто-то с менее совершенной памятью может использовать несколько классов эквивалентности здравого смысла, основанных на функциях в пределах его возможности отслеживать: размер (папа, мама, ребенок), цвет (зеленоватый, красноватый и т. д.), картина (argyle, равнина, etc.), стиль (footie, колен-высокий, etc.). Таким образом, гладильная доска будет разделена на секции для категорий. Это обычно позволяет категории находиться в постоянном времени по памяти, но тогда необходим линейный поиск по категории "ведро".

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

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

таким образом," лучший "алгоритм зависит от качества wetware/аппаратного/программного обеспечения, которое его запускает, и нашей готовности" обмануть", наложив общий порядок на пары. Конечно "лучший" мета-алгоритм заключается в найме лучших в мире носок-сортировщик: человек или машина, которая может получить и быстро хранить огромный набор N наборов атрибутов носка в 1-1 ассоциативной памяти с постоянным поиском времени, вставкой и удалением. Такие люди и машины могут быть приобретены. Если у вас есть один, вы можете соединить все носки за O(N) время для N пар, что является оптимальным. Теги total order позволяют использовать стандартное хэширование, чтобы получить тот же результат с человеческим или аппаратным компьютером.


вы пытаетесь решить не ту проблему.

Решение 1: каждый раз, когда вы кладете грязные носки в корзину для белья, завяжите их небольшим узлом. Таким образом, вам не придется делать сортировку после стирки. Подумайте об этом, как о регистрации индекса в базе данных Mongo. Немного работы впереди для некоторых сбережений CPU в будущем.

решение 2: Если это зима, вам не нужно носить соответствующие носки. Мы-программисты. Никто не должен знать, пока это работает.

решение 3: распределить работу. Вы хотите выполнить такой сложный процесс процессора асинхронно, без блокировки пользовательского интерфейса. Возьми стопку носков и засунь их в сумку. Ищите только пару, когда она вам нужна. Таким образом, объем работы, который требуется, гораздо менее заметен.

надеюсь, что это помогает!


вот нижняя граница Omega(N log n) в модели на основе сравнения. (Единственная допустимая операция-сравнение двух носков.)

предположим, что вы знаю что ваши носки 2n расположены таким образом:

p1 p2 p3 ... pn pf (1) pf (2) ... pf (n)

где F-неизвестная перестановка множества {1,2,...,северный.} Зная, что это не может сделать проблема сложнее. Есть n! возможные выходы (совпадения между первой и второй половиной), что означает, что вам нужен журнал (n!) = Omega (N log n) сравнения. Это можно получить путем сортировки.

поскольку вас интересуют связи с проблемой различимости элементов: доказательство Омеги(N log n), связанной с различимостью элементов, сложнее, потому что выход двоичный да/нет. Здесь выход должен быть совпадающим, и количество возможных выходов достаточно, чтобы получить приличную границу. Тем не менее, есть вариант, связанный с различимостью элементов. Предположим, вам дают 2n носков и интересно, могут ли они быть однозначно сопряжены. Вы можете получить сокращение от ED, отправив (a1, a2, ... таким образом,n) to (a1, a1, a2, a2, ... таким образом,n, an). (В скобках, доказательство твердости ED очень интересно,через топологию.)

Я думаю, что должно будьте Омегой (n2) привязан к исходной проблеме, если вы разрешаете только тесты равенства. Моя интуиция: рассмотрим график, где вы добавляете ребро после теста, и утверждаете, что если график не плотный, выход не определяется однозначно.


стоимость: перемещение носки - > высокий, поиск / поиск носки в строке - > маленький

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

X = ваш, Y = ваши супруги

из кучи а всех носков:

выберите два носка, поместите соответствующий носок X в линию X и носок Y в линию Y на следующем доступная позиция.

делать, пока A не опустеет.

для каждой строки X и Y

  1. выберите первый носок в строке, Поиск по строке, пока он не найдет соответствующий носок.

  2. положите в соответствуя законченную линию носков.

  3. дополнительно пока вы ищете линию и и текущий носок, на который вы смотрите, идентичен предыдущему, выполните шаг 2 для этих носки.

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

делать, пока оба X и Y не будут пустыми.

сделал

, а это имеет подобные сложности, как выбор рода, времени гораздо меньше из-за скорости ввода/вывода(перемещение носки) и Search(поиск линии на носок).

вот как я на самом деле это делаю, для p пар носков (n = 2p индивидуальные носки):

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

в худшем случае сценарий этой схемы заключается в том, что каждая пара носков достаточно различна, что она должна быть точно подобрана, и что первая n / 2 носки, которые вы выбираете, все разные. Это ваш O(n2) сценарию, и это очень вряд ли. Если количество уникальных типов носков t меньше, чем количество пар p = n / 2, и носки в каждом типе достаточно похожи (обычно в терминах, связанных с износом), что любой носок этого тип может быть сопряжен с любым другим, тогда, как я сделал вывод выше, максимальное количество носков, которые вам когда-либо придется сравнивать, - это t, после чего следующий вы тянете будет матч один из непарных носков. Этот сценарий гораздо более вероятен в среднем ящике для носков, чем в худшем случае, и уменьшает сложность худшего случая до O(n*t) где обычно t .


реальный подход:

как можно быстрее удалите носки из несортированной кучи по одному за раз и поместите в кучи перед вами. Сваи должны быть расположены несколько пространственно-эффективно, со всеми носками, направленными в одном направлении; количество свай ограничено расстоянием, которое вы можете легко достичь. Выбор стопки, на которую положить носок, должен быть-как можно быстрее-путем надевания носка на стопку, по-видимому, похожих носков; случайный тип I (надевание носок на куче, к которой он не принадлежит) или тип II (положить носок в свою собственную кучу, когда есть существующая куча таких носков), можно допустить ошибку-самое важное соображение скорость. После того, как все носки в кучах, быстро пройти через несколько носков сваи создания пар и удаления их (они направляются к ящику). Если в куче есть несоответствующие носки, повторно сложите их в лучшую (в пределах максимально быстрого ограничения) кучу. Когда все были обработаны кучи мульти-носков, соответствуют оставшимся пригодным для носки, которые не были сопряжены из-за ошибок типа II. Ух ты, ты закончила ... и у меня много носков, и я не стираю их, пока большая часть не испачкается. Еще одно практическое замечание: я переворачиваю верх одного из носков на другой, пользуясь их эластичными свойствами, чтобы они оставались вместе во время транспортировки в ящик и в то время как в ящике.


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

ответы до сих пор не делают хорошее использование наших человеческих возможностей распознавания образов. Игра Set дает ключ к тому, как это сделать хорошо: поместите все носки в двумерное пространство, чтобы вы могли их хорошо распознать и легко добраться до них руками. Это ограничивает вас в области около 120 * 80 см или около того. Оттуда выберите пары, которые вы узнаете, и удалите их. Положите дополнительные носки в свободное пространство и повторите. Если вы моете для людей с легко узнаваемыми носками (маленькие дети приходят на ум), вы можете сделать сортировку radix, выбрав сначала эти носки. Этот алгоритм хорошо работает только тогда, когда количество одиночных носков низкое


Возьмите первый носок и положите его на стол. Теперь возьмите другой носок; если он соответствует первому, положите его поверх первого. Если нет, положите его на стол на небольшом расстоянии от первой. Выберите третий носок; если он соответствует любому из предыдущих двух, поместите его поверх них или поместите его на небольшом расстоянии от третьего. Повторяйте, пока не соберете все носки.


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

машина

машина является абстракцией элемента реального мира, называемого человеком. Он способен читать из окружающей среды через пару глаз. И наша модель машины может манипулировать окружающая среда, используя 2 руки. Логические и арифметические операции вычисляются с помощью нашего мозга (надеюсь ;-)).

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

однако механическая физика дает нам некоторые лакомства. Мы не ограничиваемся лишь одним носком с рукой. Мы можем переместить сразу пару.

поэтому в зависимости от предыдущего анализа следует использовать следующие операции в порядке убывания:

  • логические и арифметические операции
  • экологические читает
  • экологические модификации

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

алгоритм

Итак, вот мое предложение:

  1. разложите все носки в куче на полу.
  2. найти пару, глядя на носки на полу.
  3. повторять от 2 до пары можно сделать.
  4. повторять от 1 до Нет носки на этаж.

операция 4 необходима, потому что при распространении носков по полу некоторые носки могут скрывать другие. Вот анализ алгоритма:

анализ

алгоритм завершается с высокой вероятностью. Это связано с тем, что на Шаге 2 невозможно найти пары носков.

для следующего анализа выполнения сопряжения n пары носков, мы предполагаем, что по крайней мере половина 2n носочки не скрыты после шага 1. Так что в среднем случае мы можем найти n/2 пар. Это означает, что цикл является шагом 4 выполняется O(log n) раза. Шаг 2 выполняется O(n^2) раза. Итак, мы можем заключить:

  • алгоритм включает в себя O(ln n + n) экологические изменения (Шаг 1 O(ln n) плюс сбор каждой пары носков с пола)
  • алгоритм включает в себя O(n^2) экологические чтения из шага 2
  • алгоритм включает в себя O(n^2) логическое и арифметические операции для сравнения носка с другим в шаге 2

Итак, у нас есть общая сложность выполнения O(r*n^2 + w*(ln n + n)) здесь r и w факторы для экологических прочитанных и экологических пишут деятельности соответственно для разумного количества носков. Стоимость логических и арифметических операций опущена, потому что мы предполагаем, что требуется постоянное количество логических и арифметических операций, чтобы решить, являются ли 2 носки принадлежат к одной паре. Это может оказаться неосуществимым в каждом сценарии.


List<Sock> UnSearchedSocks = getAllSocks();
List<Sock> UnMatchedSocks = new list<Sock>();
List<PairOfSocks> PairedSocks = new list<PairOfSocks>();

foreach (Sock newSock in UnsearchedSocks)
{
  Sock MatchedSock = null;
  foreach(Sock UnmatchedSock in UnmatchedSocks)
  {
    if (UnmatchedSock.isPairOf(newSock))
    {
      MatchedSock = UnmatchedSock;
      break;
    }
  }
  if (MatchedSock != null)
  {
    UnmatchedSocks.remove(MatchedSock);
    PairedSocks.Add(new PairOfSocks(MatchedSock, NewSock));
  }
  else
  {
    UnmatchedSocks.Add(NewSock);
  }
}

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

предпосылки: Нет никакой гарантии, что есть такие же носки. Если они одного цвета, это не значит, что у них одинаковый размер или рисунок. Носки перемешиваются случайным образом. Может быть нечетное количество носков (некоторые отсутствуют, мы не знаем сколько). Приготовьтесь запомнить переменную "index" и установить ее в 0.

результат будет иметь одну или две стопки: 1. "согласованы" и 2. "пропал"

эвристика:

  1. найти наиболее характерные носок.
  2. найти свой матч.
  3. если нет совпадения, поместите его в" недостающую " кучу.
  4. повторить с 1. пока нет более отличительных носки.
  5. если меньше 6 носков, перейдите к 11.
  6. пара вслепую все носки своему соседу (не пакуйте его)
  7. найти все совпадающие пары, упаковать его и переместить упакованные пары в" сопоставленный " кучу; Если новых совпадений не было-увеличьте "индекс" на 1
  8. если "индекс" больше 2 (это может быть значение, зависящее от носка потому что с большим количеством носки есть меньше шансов пара их вслепую) перейти к 11
  9. перетасовать остальное!--18-->
  10. на 1
  11. забыть "индекс"
  12. подобрать носок
  13. найти свою пару
  14. если нет пары для носка, переместите его в" недостающую " кучу
  15. если матч нашел пару, упакуйте пару и переместите ее в" согласованную " кучу
  16. если есть еще одна носки идут по 12
  17. если есть только один слева перейти к 14
  18. улыбка довольны :)

кроме того, может быть добавлены проверки на наличие поврежденных Носков также, как если бы удаление тех. Он может быть вставлен между 2 и 3 и между 13 и 14.

Я с нетерпением жду услышать о любом опыте или исправлениях.


носки, будь то реальные или некоторые аналогичные структуры данных, будут поставляться в парах.

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

Это решает любую вычислительную проблему сопряжения с помощью удаление его с помощью слоя абстракции.

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

там есть две физические возможности:--1-->

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

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

http://www.aliexpress.com/compare/compare-invisible-snap-buttons.html

тогда все вы сделайте это, защелкните носки вместе сразу после того, как вы снимаете их и кладете в корзину для стирки, и снова вы удалили проблему необходимости пары носков с физической абстракцией концепции "пары".


когда я сортирую носки, я делаю приблизительную сортировка radix, падая носки около других носков такого же типа цвета/картины. За исключением случая, когда я вижу точное совпадение в/около места, где я собираюсь бросить носок, я извлекаю пару в этот момент.

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

Я делаю это:

  1. выбор отличительного носка (все, что бросается в глаза первым в куче).
  2. запуск сортировки radix из этого концептуального местоположения, потянув носки из кучи на основе сходства с этим.
  3. поместите новый носок рядом с текущей кучей, с расстоянием, основанным на том, насколько он отличается. Если вы обнаружите, что кладете носок поверх другого, потому что он идентичен, сформируйте пару и удалите их. Это означает, что будущие сравнения требуют меньше усилий, чтобы найти правильное место.

Это использует человеческую способность нечеткого соответствия в O (1) времени, что несколько эквивалентно установлению хэш-карты на вычислительном устройстве.

потянув отличительные носки сначала, вы оставляете пространство для "увеличения" на функциях, которые являются менее отличительными, для начала.

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

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


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

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


рассмотрим хэш-таблицу размера 'N'.

Если мы предполагаем нормальное распределение, то оценочное количество "вставок", чтобы иметь по крайней мере один носок, сопоставленный с одним ведром, - NlogN (т. е. все ведра заполнены)

Я получил это как часть головоломки,но я был бы счастлив ошибиться. вот моя статья в блоге о том же

пусть' N ' соответствует приблизительной верхней границе числа уникальных цвета / узор носков, которые у вас есть.

после столкновения(a.к. a: a match) просто удалите эту пару носков. Повторите тот же эксперимент со следующей партией носков NlogN. Красота этого заключается в том, что вы можете делать параллельные сравнения NlogN(разрешение столкновений) из-за того, как работает человеческий ум. :-)


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

Я обнаружил, что интеграция процесса сортировки в подвешивание для сушки делает его легким. Мне все равно нужно поднять каждый носок и повесить его (переместить), и мне ничего не стоит повесить его в определенном месте на струнах. Сейчас просто нет чтобы принудительно выполнить поиск всего буфера (строк), Я выбираю размещение носков по цвету/оттенку. Более темный левый, более яркий правый, более красочный фронт etc. Теперь, прежде чем повесить каждый носок, я смотрю в его "правильной близости", если соответствующий уже есть - это ограничивает "сканирование" 2-3 другими носками - и если это так, я вешаю другой рядом с ним. Затем я скатываю их в пары, снимая со струн, когда они высохнут.

теперь это не может показаться все, что отличается от " формирования свай по цвету" предложенный top answers, но сначала, не выбирая дискретные сваи, а диапазоны, у меня нет проблем с классификацией, идет ли "фиолетовый" в "красный" или "синий"; он просто идет между ними. А затем, интегрируя две операции (повесить сушить и сортировать), накладные расходы на сортировку во время подвешивания составляют 10% от того, что было бы отдельной сортировкой.


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

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

  1. люди бросают оба из их носков грубо в такой же зоне бин,
  2. ящик не рандомизирован в любой момент, и поэтому
  3. любое подмножество, взятое из верхней части этого Бина, обычно содержит оба пара носков.

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

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

вот алгоритм для put_socks_on_line():

while (socks left in basket) {
 take_sock();
 if (cluster of similar socks is present) { 
   Add sock to cluster (if possible, next to the matching pair)
 } else {
  Hang it somewhere on the line, this is now a new cluster of similar-looking socks.      
  Leave enough space around this sock to add other socks later on 
 }
}

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

вот алгоритм take_socks_from_line():

while(socks left on line) {
 take_next_sock();
 if (matching pair visible on line or in basket) {
   Take it as well, pair 'em and put 'em away
 } else {
   put the sock in the basket
 }

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

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

вот алгоритм для sort_remaining_clusters():

while(clusters present in basket) {
  Take out the cluster and spread it
  Process it immediately
  Leave remaining socks where they are
}

после этого осталось всего несколько носков. Именно здесь я ввожу ранее непарные носки в систему и обрабатываю оставшиеся носки без какого - либо специального алгоритма-оставшихся носков очень мало и могут быть обработаны визуально очень быстро.

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

Я знаю, что эти алгоритмы принимают много предположений: ящик, который действует как своего рода стопка ЛИФО, ограниченная, нормальная стиральная машина и ограниченная, нормальная бельевая веревка - но это все еще работает с очень большим количеством носков.

о параллельности: Пока вы бросаете оба носка в одну корзину, вы можете легко выполнять все эти шаги.


Я предпринял простые шаги, чтобы уменьшить свои усилия в процесс, занимающий O (1) Время.

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

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

такие предварительные усилия были замечены много раз в очень популярном и эффективном коде. Примеры включают #DEFINE'ING pi до нескольких десятичных знаков (другие примеры существуют, но это тот, который приходит на ум прямо сейчас).


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


проблема сортировки ваши N пар носков-O (n). Прежде чем бросить их в прачечную корзина, вы нанизываете левый на правый. Вынимая их, вы разрезаете нить и кладете каждую пару в ящик - 2 операции на n парах, так что O(n).

теперь следующий вопрос - просто ли вы сами стираете, а ваша жена стирает свою. Это проблема, вероятно, в совершенно другая область проблем. :)


Я закончил сопряжение моих носков прямо сейчас, и я обнаружил, что лучший способ сделать это следующее:

  • Выберите один из носков и уберите его (создайте "ведро"для этой пары)
  • Если следующий является парой предыдущего, то поместите его в существующее ведро, иначе создайте новое.

в худшем случае это означает, что у вас будет n / 2 разных ведра, и у вас будет n-2 Определения о том, какое ведро содержит пару текущего носка. Очевидно, что этот алгоритм работает хорошо, если у вас всего несколько пар; я сделал это с 12 парами.

Это не так научно, но это работает хорошо:)


мое решение не совсем соответствует вашим требованиям, так как оно формально требует O(n) "дополнительные" места. Однако, учитывая мои условия, это очень эффективно в моем практическом применении. Поэтому я думаю, что это должно быть интересно.

объединить с другой задачей

особое условие в моем случае заключается в том, что я не использую сушильную машину, просто повесьте мои ткани на обычную сушилку. Висячие ткани требует O(n) операции (кстати, я всегда считаю бин упаковка проблема здесь), и проблема по своей природе требует линейного "дополнительного" пространства. Когда я беру новый носок из ведра, я пытаюсь повесить его рядом с его парой, если пара уже висит. Если это носок от новой пары, я оставляю рядом с ним место.

Oracle машина лучше ; -)

это, очевидно, требует дополнительной работы, чтобы проверить, есть ли соответствующий носок, уже висящий где-то, и он будет отображать решение O(n^2) с коэффициентом о 1/2 для компьютера. Но в этом случае "человеческий фактор" на самом деле является преимуществом - я обычно могу очень быстро (почти O(1)) определите соответствующий носок, если он уже висел (возможно, какое-то незаметное кэширование в мозге) - считайте его своего рода ограниченным "оракулом", как в Машина Oracle ; -) мы, люди, имеем эти преимущества перед цифровыми машинами в некоторых случаях; -)

почти O(n)!

подключение проблема сопряжения носков с проблемой подвешивания тканей, которые я получаю O(n) "дополнительное пространство" бесплатно, и есть решение, которое о O(n) вовремя, требует немного больше работы, чем простые висячие ткани и позволяет сразу получить доступ к полной паре носков даже в очень плохое утро понедельника... ;-)