Размещение людей в кинотеатре - PullRequest
14 голосов
/ 21 октября 2011

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

Общий вопрос:

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

Технический вопрос:

Учитывая Nпо сетке M заполните сетку N * M - 1 пунктами.Каждый элемент имеет логическое значение ассоциации для каждого из остальных элементов N * M - 2.В каждой строке N элементы, расположенные непосредственно рядом с другими элементами, должны иметь положительное значение связи для другого.Колонны, однако, не имеют значения, то есть предмет может быть «врагом», если предмет находится перед ним. Примечание: Если элемент A имеет положительное значение ассоциации для B, то это означает, что B также имеет положительное значение ассоциации для A. Он работает так же для отрицательных значений ассоциации.Гарантируется, что предмет имеет положительную связь, по крайней мере, с одним другим предметом. Также , у вас есть доступ ко всем элементам и их значениям ассоциации, прежде чем вы начнете размещать их в сетке.

Комментарии:

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

Насколько моя реализация пошла, я сделал N = 10, M = 10, количество элементов = 99 и имел массив размером 99 для каждого элемента, который имел случайное логическое значение, которое ссылалось надружба с соответствующим номером товара.Это означает, что у каждого предмета была ценность дружбы, которая соответствовала его самому себе, я просто проигнорировал это значение.

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

Ответы [ 2 ]

9 голосов
/ 21 октября 2011

Эта проблема NP-Hard .
Define L={(G,n,m)|there is a legal seating for G in m×m matrix,(u,v) in E if u is friend of v} L является формальным определением этой проблемы как языка.

Доказательство:
Мы покажем Гамильтонова задача ≤ (p) 2-путь ≤ (p) Эта задача в 2 этапа [Гамильтониан и 2-путь определены ниже], и, таким образом, мы заключаем, что эта задача является NP-трудной.

(1) Мы покажем, что поиск двух путей, охватывающих все вершины без использования одной вершины дважды, является NP-сложным [назовем такой путь: 2-путь, и эта задача - как задача 2-пути]
Сокращение от задачи о гамильтоновом пути :

input: a graph G=(V,E)
Output: a graph G'=(V',E) where V' = V U {u₀}.

Корректность:

  • если G имеет гамильтонов путь: v₁ → v₂ → ... → vn, то G 'имеет 2-путь: v₁ → v₂ → ... → уп, u₀
  • если G 'имеет 2-путь, так как u₀ изолирован от остальных вершин, существует путь: v₁ → ... → vn, который является гамильтонианом в G.

Таким образом: у G есть гамильтонов путь 1 ⇔ G имеет 2 пути, и, таким образом: задача с 2 путями NP-Hard.

(2) Теперь мы покажем, что наша задача [L] также NP-Hard:
Мы покажем сокращение от задачи с 2 путями, определенной выше.

input: a graph G=(V,E)
output: (G,|V|+1,1) [a long row with |V|+1 sits].

Корректность:

  • Если у G есть 2 пути, то мы можем усадить людей и использовать 1 место для использовать в качестве «буфера» между двумя путями, это будет законное идеальное размещение так как если v₁ сидит рядом с v₂, то v₁ v₁ → v₂ находится на пути, и, таким образом, (v₁, v₂) находится в E, поэтому v₁, v₂ - друзья.
  • Если (G, | V | +1,1) является законным местом: [v₁, ..., vk, буфер , vk + 1, ..., vn], существует 2-дорожка в G, v₁ → ... → vk, vk + 1 → ... → vn

Вывод: Эта проблема является NP-Hard, поэтому для нее нет полиномиального решения.

Экспоненциальное решение: Возможно, вы захотите использовать решение backtracking : в основном: создайте все подмножества E с размером | V | -2 или меньше, отметьте, какое лучше.

static best <- infinity
least_enemies(G,used):
  if |used| <= |V|-2:
     val <- evaluate(used)
     best <- min(best,val)
  if |used| == |V|-2: 
     return
  for each edge e in E-used: //E without used 
     least_enemies(G,used + e)

здесь мы предполагаем, что оценка (использованная) дает «оценку» для этого решения. если это решение полностью незаконно [т.е. вершина появляется дважды], evaluate(used)=infinity. Конечно, можно сделать оптимизацию, обрезав эти случаи. чтобы получить фактическое заседание, мы можем сохранить лучшее на данный момент решение.

(*) Возможно, есть лучшие решения, это просто простое возможное решение, основная цель в этом ответе - доказательство эта проблема - NP-Hard.

РЕДАКТИРОВАТЬ: более простое решение:
Создайте график G'=(V U { u₀ } ,E U {(u₀,v),(v,u₀) | for each v in V}) [u₀ - это ненужная вершина для буфера] и весовую функцию для ребер:

w((u,v)) = 1    u is friend of v
w((u,v)) = 2    u is an enemy v
w((u0,v)) = w ((v,u0)) = 0

Теперь у вас есть классический TSP , который можно решить в O(|V|^2 * 2^|V|) с помощью динамического программирования.

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

0 голосов
/ 22 октября 2011

Один алгоритм, используемый для больших «пространств поиска», таких как имитация отжига

...