2009-10-24 4 views
2

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

Например, учитывая множество 2 3 3 5:

2 | 3 3 5 
2 | 3 | 3 5 
2 | 3 3 | 5 
2 | 3 | 3 | 5 
2 5 | 3 3 

и так далее. Практически все возможные комбинации членов набора. Конечно, я обыскал сеть, но не нашел много полезного для меня, так как я говорю программист-ese not advanced-math-ese.

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

+0

На самом деле, эти списки, не устанавливает. Сожалею. Будут повторяющиеся значения. –

+0

В чем проблема, над которой вы работаете? –

+0

159, но я оставлю его вам, почему я хочу этот алгоритм –

ответ

2

Вы считаете дерево поиска? Каждый узел будет представлять собой выбор того, где поставить элемент, а листовые узлы - это ответы. Я не буду давать вам код, потому что это часть удовольствия от Project Euler;)

+0

Обратите внимание, что разбиение списка - это * не * проблема Эйлера Проекта и не решит его. Это всего лишь промежуточный шаг. –

0

Ну, проблема имеет два аспекта.

Прежде всего, предметы могут быть организованы в любом порядке. Итак, для N элементов есть N! перестановки (при условии, что элементы рассматриваются как уникальные).
Во-вторых, вы можете представить группировку как бит-флаг между каждым элементом, указывающим разделение. Там был бы N-1 этих флагов, поэтому для данной перестановки были бы 2^(N-1) возможные группировки.
Это означает, что для N элементов будет общее число N! * (2^(N-1)) группировок/перестановок, которое становится очень быстрым.

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

2 на 3 от 3 от 5
2 на 3 на 3 от 5
2 на 3 от 3 по 5
2 на 3 на 3 на 5
2 от 5 on 3 off 3

Перестановки (порядок отображения) могут быть получены путем просмотра их как дерева, как упомянуто двумя другими. Это почти наверняка будет включать рекурсию, такую ​​как here. Группировка не зависит от них разными способами. Если у вас есть все перестановки, вы можете связать их с группами, если это необходимо.

+0

Я думаю, вы имеете в виду 2^(N-1) вместо (N-1)^2. Что еще более важно, порядок обычно игнорируется для разбиения (2 | 3 3 5 совпадает с 3 5 3 | 2), поэтому ваша формула является только верхней границей. – xan

+0

Упс, теперь исправлено. – MartW

-1

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

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

Во всяком случае, вот код питона:

import time 

def separate(toseparate): 
    "Find every possible way to separate a given list." 
    #The list of every possibility 
    possibilities = [] 
    n = len(toseparate) 
    #We can distribute n-1 separations in the given list, so iterate from 0 to n 
    for i in xrange(n): 
    #Create a copy of the list to avoid modifying the already existing list 
    copy = list(toseparate) 
    #A boolean list indicating where a separator is put. 'True' indicates a separator 
    #and 'False', of course, no separator. 
    #The list will contain i separators, the rest is filled with 'False' 
    separators = [True]*i + [False]*(n-i-1) 
    for j in xrange(len(separators)): 
     #We insert the separators into our given list. The separators have to 
     #be between two elements. The index between two elements is always 
     #2*[index of the left element]+1. 
     copy.insert(2*j+1, separators[j]) 
    #The first possibility is, of course, the one we just created 
    possibilities.append(list(copy)) 
    #The following is a modification of the QuickPerm algorithm, which finds 
    #all possible permutations of a given list. It was modified to only permutate 
    #the spaces between two elements, so it finds every possibility to insert n 
    #separators in the given list. 
    m = len(separators) 
    hi, lo = 1, 0 
    p = [0]*m 
    while hi < m: 
     if p[hi] < hi: 
     lo = (hi%2)*p[hi] 
     copy[2*lo+1], copy[2*hi+1] = copy[2*hi+1], copy[2*lo+1] 
     #Since the items are non-unique, some possibilities will show up more than once, so we 
     #avoid this by checking first. 
     if not copy in possibilities: 
      possibilities.append(list(copy)) 
     p[hi] += 1 
     hi = 1 
     else: 
     p[hi] = 0 
     hi += 1 
    return possibilities 

t1 = time.time() 
separations = separate([2, 3, 3, 5]) 
print time.time()-t1 
sepmap = {True:"|", False:""} 
for a in separations: 
    for b in a: 
    if sepmap.has_key(b): 
     print sepmap[b], 
    else: 
     print b, 
    print "\n", 

Он основан на алгоритме QuickPerm, который вы можете прочитать больше о здесь: QuickPerm

В принципе, мой код создает список, содержащий п разделения, вставки их в данный список, а затем находит все возможные перестановки разделов в списке.

Таким образом, если мы используем ваш пример мы получим:

2 3 3 5 
2 | 3 3 5 
2 3 | 3 5 
2 3 3 | 5 
2 | 3 | 3 5 
2 3 | 3 | 5 
2 | 3 3 | 5 
2 | 3 | 3 | 5 

In +0,000154972076416 секунд.

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

+0

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

+0

2 5 | 3 3 и тому подобное отсутствуют. – starblue

0

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

Теперь даже recursion for the number of partitions of some identical items довольно сложный.

Для разделов мультимножеств подсчет сводится к решению обобщения Project Euler problem 181 на произвольные мультимножества.

0

Вот код, который нужен для этой части вашей проблемы:

def memoize(f): 
    memo={} 
    def helper(x): 
     if x not in memo: 
      memo[x]=f(x) 
     return memo[x] 
    return helper 

@memoize 
def A000041(n): 
    if n == 0: return 1 
    S = 0 
    J = n-1 
    k = 2 
    while 0 <= J: 
     T = A000041(J) 
     S = S+T if k//2%2!=0 else S-T 
     J -= k if k%2!=0 else k//2 
     k += 1 
    return S 

print A000041(100) #the 100's number in this series, as an example 
Смежные вопросы