Лучший алгоритм для приглашения людей на вечеринку

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

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

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

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

У разных сотрудников могут быть общие начальники в командной цепочке. Вы НЕ получаете дополнительную ценность за влияние на человека более одного раза. Например, если A и B оба подчиняются непосредственно генеральному директору, и вы влияете на обоих, вы получите значение val(A)+val(B)+val(CEO), а не val(A)+val(B) +2val(генеральный директор).

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

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


person Agir Mahad    schedule 12.11.2014    source источник
comment
Это немного сложнее, чем выбирать самых низших людей в иерархическом смысле: у некоторых из них может быть общий предок!   -  person Rerito    schedule 12.11.2014
comment
Точно. Один из подходов, который я пробовал, заключался в том, чтобы перебрать этих сотрудников самого низкого уровня, выбрать максимальное и обновить значения других, но это все еще очень медленно и определенно не оптимально.   -  person Agir Mahad    schedule 12.11.2014
comment
Чтобы уточнить, какое ограничение — количество людей, которые могут посетить вечеринку, или количество приглашений, которые вы можете написать? (Не то же самое, потому что некоторые люди получают косвенное приглашение)   -  person Colonel Panic    schedule 17.11.2014
comment
ОП, ты пробовал жадный алгоритм? Можете ли вы доказать, что это оптимально? Если нет, то когда это пойдет не так? Вдохновляет ли это новый алгоритм?   -  person Colonel Panic    schedule 17.11.2014
comment
Голосуйте, чтобы оставить открытым — это хорошо написанная и тщательно определенная проблема алгоритмов. (Хотя было бы лучше с примером.)   -  person Colonel Panic    schedule 17.11.2014


Ответы (3)


Пусть V[e, k] будет максимальным значением выдачи k приглашений e и его прямым и косвенным подчиненным, игнорируя значение всех прямых и косвенных начальников e. Если у сотрудника e нет подчиненных, то базовый случай

V[e, k], k = 0 = 0
V[e, k], k > 0 = val(e).

Если у сотрудника e0 есть два подчиненных, e1 и e2, то повторение равно

V[e0, k], k = 0 = 0
V[e0, k], k > 0 = max over j of val(e0) + V[e1, j] + V[e2, k - j].

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

person David Eisenstat    schedule 12.11.2014
comment
@David - определенно оптимально выбрать сотрудника с наибольшей предельной ценностью. У вас есть какой-нибудь псевдокод, чтобы показать, что это можно сделать менее чем за O (n ^ k)? Это был бы подход грубой силы. - person Agir Mahad; 12.11.2014
comment
@AgirMahad: Если вы отметите уже приглашенных людей, то для оценки конкретного человека вам просто нужно пройти вверх по дереву, пока вы не нажмете первого уже приглашенного человека (каждый человек выше этого обязательно тоже уже приглашен). Это займет не более n шагов, и не более n человек должны набрать очки, поэтому поиск лучшего человека для добавления будет в худшем случае O (n ^ 2). Есть k шагов, так что в целом это O (kn ^ 2). - person j_random_hacker; 12.11.2014
comment
На самом деле @Nemo кажется правым. На этой странице в Википедии даже упоминается проблема максимального покрытия, которая является NP-сложной и представляет собой лишь небольшое обобщение этой проблемы. - person j_random_hacker; 12.11.2014
comment
@j_random_hacker Да, я не сплю. Ответ был полностью переписан. - person David Eisenstat; 12.11.2014
comment
@DavidEisenstat - не уверен, что понимаю, что вы подразумеваете под свертыванием? Я понимаю базовые случаи и случай, когда есть два сотрудника, но я не уверен, что вы имеете в виду, как расширить это до нескольких подчиненных (3, 4 или более). Любая дополнительная помощь была бы потрясающей. Спасибо за то, что вы помогаете мне лучше понять. Обновление: ваше повторение для 2 подчиненных O (nk ^ 2)? - person Agir Mahad; 12.11.2014
comment
@AgirMahad Да, твоему обновлению. Наивная 3-подчиненная версия будет max over j1, j2 of val(e0) + V[e1, j1] + V[e2, j2] + V[e3, k - j1 - j2], что равно O(nk^3). Чтобы экспонента не раздувалась из-за большего количества подчиненных, мы переписываем в max over j1 of max over j2 of ..., а затем разделяем кучу вычислений для внутреннего максимума. - person David Eisenstat; 13.11.2014
comment
@DavidEisenstat Значит ли это, что O(nk^2) лучший? Я думаю, что, возможно, придумал подход O (nk), но не уверен, что он работает. Я пытался придумать подход «разделяй и властвуй», при котором я делю иерархию на подчиненных, но нет четкого способа определить, что лучше, не достигнув сначала нижней части этого соответствующего пути. Его также можно было бы преобразовать в задачу о самом длинном пути, но тогда это будет приблизительно время выполнения O(nk^2 + ..). Еще раз спасибо за вашу помощь. - person Agir Mahad; 13.11.2014

Изменить: этот ответ предполагает, что все значения для приглашения людей неотрицательны.

Эту задачу можно решить с помощью жадного алгоритма. Давайте сначала обсудим случай, когда все значения равны, поэтому мы просто пытаемся пригласить максимальное количество людей. Ключевое наблюдение заключается в том, что в любом оптимальном решении вы всегда должны выбирать человека с наибольшим количеством прямых или косвенных начальников. Вот краткое объяснение того, почему: предположим, что у человека X больше начальников, и у вас есть выборки, не включающие человека X. Рассмотрите человека Y среди ваших выборов, у которого больше всего начальников с X. Затем вы можете добиться большего успеха, выбрав X вместо Y.

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

       A
   B       C
 D   E   F   G
H I J K L M N O

Наш первый выбор будет H, что автоматически дает нам D, B и A. Затем остается выбрать 2 из трех деревьев

I   E      C
   J K   F   G
        L M N O

Следующий лучший выбор — L и так далее.

Мы можем сделать это эффективно, потому что нам просто нужно отслеживать самого глубокого потомка (не обязательно прямого потомка) каждого узла, который мы можем вычислить заранее. Затем нам нужна какая-то структура данных очереди приоритетов, чтобы выбрать лучшее дерево для выбора. Если вы выбираете k людей из иерархии размером n, это должно дать алгоритм O(n + k log n).

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

person arghbleargh    schedule 15.11.2014
comment
Я думаю, что есть проблема с жадным подходом, если значение узла может быть отрицательным. - person Jason L; 17.11.2014
comment
Хорошо, это работает только в том случае, если значения неотрицательны, что я и предполагал. Но я думаю, проблема имеет смысл и с отрицательными значениями. - person arghbleargh; 18.11.2014

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

  • Первая итерация охватит всех в компании, где вы определите, кто является генеральным директором, а кто находится непосредственно под ним.
  • В качестве начального набора компонентов возьмите каждого из начальников непосредственно ниже генерального директора.
  • Затем для каждого другого человека вы будете использовать dfs, чтобы связать их с боссом 2-го уровня (это динамический подход).
  • Вы хотите сделать эту последнюю часть таким образом, что если person F является боссом person E, который, в свою очередь, является боссом person D, ... вплоть до person A, то вы хотите, чтобы после dfs можно было сказать через O(1) раз этот человек F становится начальником человека A и наоборот.

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

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

person smac89    schedule 15.11.2014