Равномерное распределение всех элементов в списке

У меня была эта проблема некоторое время, все еще пытаясь работать над решением.

Каков наилучший способ равномерного распределения элементов в списке с низким расхождением?

Скажем, у нас есть список или элементы в массиве:

Red, Red, Red, Red, Red, Blue, Blue, Blue, Green, Green, Green, Yellow

В идеале вывод будет иметь нечто вроде:

Red, Blue, Red, Green, Red, Yellow, Blue, Red, Green, Red, Blue, Green.

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

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

Предложение началось с элемента с наивысшей частотой, поэтому красный будет помещен в положение n * 12/5 для n от 0 до 4 включительно.

Затем поместите следующий наиболее повторяющийся элемент (синий) в положения n * 12/3 + 1 для n от 0 до 2 включительно. Если что-то уже размещено там, просто поставьте его на следующее пустое место. и т.д. Однако при записи на бумаге это не работает при любых обстоятельствах,

Скажите, что список только

Red, Red, Red, Red, Red, Blue

Это не сработает.

Если в одной из опций есть три соседства с цветом

Red, Red, Blue, Red, Red, Red
Red, Red, Red, Blue, Red, Red

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

Если это важно, я работаю над objective-c, но сейчас все, о чем я забочусь, это методология, как это сделать.

Ответ 1

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

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

Обновление: возможно, это может сделать его лучше: получить размер самого большого списка при запуске алгоритма и назвать его LARGEST_SIZE - этот будет проходить в каждом раунде. Теперь для всех других списков они должны использоваться только в раундах starting_size_of_the_list/LARGEST_SIZE. Надеюсь, ты знаешь, что я имею в виду. Таким образом, вы должны иметь возможность равномерно размещать все предметы. Но, тем не менее, он все еще не идеален!

ОК, поэтому я постараюсь быть более конкретным. Скажем, у вас есть 4 списка размеров: 30 15 6 3

В первом списке вы будете использовать его каждые 30/30 раунда, что равно 1, поэтому каждый 1 раунд. Это означает каждый раз. Во втором списке вы будете использовать его 15/30, равное 0,5, каждые 2 раунда. третий список: 6/30 → каждые 5 раундов. Последний список: 3/30 → каждые 10 раундов. Это должно действительно дать вам приятное расстояние между пунктами.

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

Ответ 2

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

Пример:

  • 5 & times; B: цифры (1/10 3/10 5/10 7/10 9/10)
  • 3 & times; R: цифры (1/6 3/6 5/6)
  • отсортировано: ((1/10 "B" ) (1/6 "R" ) (3/10 "B" ) (5/10 "B" ) (3/6 "R" ) (7/10 "B" ) (5/6 "R" ) (9/10 "B" ))
  • = > B R B B R B R B

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

Обратите внимание, что отдельные последовательности уже отсортированы, поэтому вы можете сортировать путем слияния, а именно O (n & middot; log m) в этом случае (n - сумма всех значений, m - количество цветов). Это может быть дополнительно оптимизировано путем генерации чисел лениво.

Окончательный алгоритм не нуждается в явной сортировке:

  • установите для счетчика B значение (/(* 2 5)) = > 1/10
  • установите для счетчика R значение (/(* 2 3)) = > 1/6
  • установите шаг B, чтобы удвоить счетчик B
  • установите шаг R, чтобы удвоить счетчик R
  • цикл
    • возьмите один из цветов с самым низким счетчиком и поместите его в свой результат.
    • шаг, который счетчик по ширине шага
    • пока все счетчики не будут >= 1

Так как вам нужно n шагов цикла, и каждый раз приходится находить минимум m чисел, это, похоже, работает на O (n & middot; m). Тем не менее, вы можете сохранить счетчики в минимальной куче, чтобы снова довести ее до O (n & middot; log m).

Ответ 3

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

У вас будет максимальная куча пар (COUNTER, COLOR), порядок от COUNTER, так что цвет с самым большим COUNTER будет на вершине. Каждый раз, когда у вас будет два случая: если значение в верхней части не совпадает с последним элементом в списке, вы удалите из кучи пару (COUNTERx, COLOURx), добавьте COLOURx в конец списка, и добавьте пару ((COUNTERx) - 1, COLOURx) в кучу, если (COUNTERx) - 1!= 0. В другом случае возьмите вторую самую большую пару COUNTER из кучи вместо первой и сделайте то же самое, что и для первой пары, Сложность времени - o (S log N), где N - количество цветов, а S - размер списка.

Ответ 4

Вы можете сделать обратный кластеризация K-, направленную на:

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

Ответ 5

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

Ответ 6

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