Алгоритм для создания набора spanning
Учитывая этот ввод: [1,2,3,4]
Я хотел бы сгенерировать набор охватывающих множеств:
[1] [2] [3] [4]
[1] [2] [3,4]
[1] [2,3] [4]
[1] [3] [2,4]
[1,2] [3] [4]
[1,3] [2] [4]
[1,4] [2] [3]
[1,2] [3,4]
[1,3] [2,4]
[1,4] [2,3]
[1,2,3] [4]
[1,2,4] [3]
[1,3,4] [2]
[2,3,4] [1]
[1,2,3,4]
В каждом наборе есть все элементы исходного набора, помещенные в уникальные подмножества. Каков алгоритм, создающий эти множества? Я пробовал функции генератора Python, используя выбор, перестановку, комбинацию, набор мощности и т.д., Но не могу получить правильную комбинацию.
20 янв 2009
Это не вопрос домашней работы. Это улучшенный ответ, который я работал над проблемой www.projecteuler.net # 118. У меня уже было медленное решение, но придумал лучший способ - кроме того, что я не мог понять, как сделать набор spanning.
Я отправлю свой код, когда вернусь из Инаугурации.
21 янв 2009
Это возможный алгоритм, который я использовал:
def spanningsets(items):
if len(items) == 1:
yield [items]
else:
left_set, last = items[:-1], [items[-1]]
for cc in spanningsets(left_set):
yield cc + [last]
for i,elem in enumerate(cc):
yield cc[:i] + [elem + last] + cc[i+1:]
@Yuval F: Я знаю, как сделать poweret. Здесь простая реализация:
def powerset(s) :
length = len(s)
for i in xrange(0, 2**length) :
yield [c for j, c in enumerate(s) if (1 << j) & i]
return
Ответы
Ответ 1
Это должно работать, хотя я не проверял его достаточно.
def spanningsets(items):
if not items: return
if len(items) == 1:
yield [[items[-1]]]
else:
for cc in spanningsets(items[:-1]):
yield cc + [[items[-1]]]
for i in range(len(cc)):
yield cc[:i] + [cc[i] + [items[-1]]] + cc[i+1:]
for sset in spanningsets([1, 2, 3, 4]):
print ' '.join(map(str, sset))
Вывод:
[1] [2] [3] [4]
[1, 4] [2] [3]
[1] [2, 4] [3]
[1] [2] [3, 4]
[1, 3] [2] [4]
[1, 3, 4] [2]
[1, 3] [2, 4]
[1] [2, 3] [4]
[1, 4] [2, 3]
[1] [2, 3, 4]
[1, 2] [3] [4]
[1, 2, 4] [3]
[1, 2] [3, 4]
[1, 2, 3] [4]
[1, 2, 3, 4]
Ответ 2
Как насчет этого? Я еще не тестировал его, но я попробую его позже...
Я думаю, что этот метод называется динамическим программированием:
-
Возьмите первый элемент [1]
Что вы можете создать с ним? Только [1]
-
Возьмите второй [2]
Теперь у вас есть две возможности: [1,2]
и [1] [2]
-
Возьмите третий [3]
С первым номером 2 [1,2]
можно создать [1,2,3]
и [1,2] [3]
Со вторым номером 2 [1] [2]
можно создать [1,3] [2]
и [1] [2,3]
и [1] [2] [3]
Надеюсь, это достаточно ясно, что я пытался показать. (Если нет, оставьте комментарий!)
Ответ 3
Здесь Страница репозитория алгоритма SUNY. Возможно, вы можете перевести одну из ссылок на код на python.
Изменить: Это была аналогичная проблема. Здесь - это страница репозитория SUNY о создании разделов, которая, я считаю, является правильной проблемой.
Ответ 4
Я думаю, что следующий метод - лучший способ сгенерировать их для проблемы с эйлером, так как вы можете заменить возвращаемое значение числом простых охватывающих подмножеств, и будет тривиально делать умножение (особенно с memoization):
GenerateSubsets(list)
partitions = { x | x is subset of list and x contains the lowest element of list }
foreach (parition in partitions)
if set == list
yield { partition }
else
yield { partition } x GenerateSubsets(list - part)
Основная часть состоит в том, чтобы убедиться, что рекурсивная сторона всегда имеет самый левый элемент, таким образом, вы не получаете дубликатов.
У меня есть грязный код С#, который делает это:
IEnumerable<IEnumerable<List<int>>> GenerateSubsets(List<int> list)
{
int p = (1 << (list.Count)) - 2;
List<int> lhs = new List<int>();
List<int> rhs = new List<int>();
while (p >= 0)
{
for (int i = 0; i < list.Count; i++)
if ((p & (1 << i)) == 0)
lhs.Add(list[i]);
else
rhs.Add(list[i]);
if (rhs.Count > 0)
foreach (var rhsSubset in GenerateSubsets(rhs))
yield return Combine(lhs, rhsSubset);
else
yield return Combine(lhs, null);
lhs.Clear();
rhs.Clear();
p -= 2;
}
}
IEnumerable<List<int>> Combine(List<int> list, IEnumerable<List<int>> rest)
{
yield return list;
if (rest != null)
foreach (List<int> x in rest)
yield return x;
}
Ответ 5
Результат, созданный вместе с пустым множеством {}, выглядит как результат poweret (или набор мощности), но это не то же самое.
Я начал сообщение о подобной проблеме, которая имеет несколько реализаций (хотя и на С#) и в некоторых случаях ориентирована скорее на скорость, чем на ясность. Первый пример должен быть легко перевести. Возможно, в любом случае это даст несколько идей.
Они работают по принципу, что emmumerating комбинации аналогичны счету в двоичном (представьте, считая от 0 до 16). Вы не указываете, является ли заказ важным или просто генерируют все комбинации, поэтому после этого может быть в порядке.
Здесь посмотрите (игнорируйте нечетное название, обсуждение заняло другое направление)