Порядок подмножества сумм


22

Набор nположительных чисел имеет 2^nподмножества. Мы назовем набор «хорошим», если ни одно из этих подмножеств не имеет одинаковую сумму. {2, 4, 5, 8}один такой хороший набор. Поскольку ни одно из подмножеств не имеет одинаковую сумму, мы можем отсортировать подмножества по сумме:

[{}, {2}, {4}, {5}, {2, 4}, {2, 5}, {8}, {4, 5}, {2, 8}, {2, 4, 5}, {4, 8}, {5, 8}, {2, 4, 8}, {2, 5, 8}, {4, 5, 8}, {2, 4, 5, 8}]

Если мы помечаем числа [2, 4, 5, 8]символами [a, b, c, d]в возрастающем порядке, мы получаем следующий абстрактный порядок:

[{}, {a}, {b}, {c}, {a, b}, {a, c}, {d}, {b, c}, {a, d}, {a, b, c}, {b, d}, {c, d}, {a, b, d}, {a, c, d}, {b, c, d}, {a, b, c, d}]

Другой хороший набор положительных чисел может иметь такой же абстрактный порядок или другой. Например, [3, 4, 8, 10]это хороший набор с другим абстрактным порядком:

[{}, {a}, {b}, {a, b}, {c}, {d}, {a, c}, {b, c}, {a, d}, {b, d}, {a, b, c}, {a, b, d}, {c, d}, {a, c, d}, {b, c, d}, {a, b, c, d}]

В этом задании вы должны посчитать количество различных абстрактных порядков хороших наборов nположительных чисел. Эта последовательность OEIS A009997 , и известные значения, начиная с n=1:

1, 1, 2, 14, 516, 124187, 214580603

Например, для n=3, следующие два возможных абстрактных порядка:

[{}, {a}, {b}, {c}, {a, b}, {a, c}, {b, c}, {a, b, c}]
[{}, {a}, {b}, {a, b}, {c}, {a, c}, {b, c}, {a, b, c}]

Для n=4, являются следующими 14 возможной абстрактной упорядоченностью, а также пример хорошего набора с этим упорядочением:

[{}, {a}, {b}, {a, b}, {c}, {a, c}, {b, c}, {a, b, c}, {d}, {a, d}, {b, d}, {a, b, d}, {c, d}, {a, c, d}, {b, c, d}, {a, b, c, d}], [8, 4, 2, 1]                                       
[{}, {a}, {b}, {a, b}, {c}, {a, c}, {b, c}, {d}, {a, b, c}, {a, d}, {b, d}, {a, b, d}, {c, d}, {a, c, d}, {b, c, d}, {a, b, c, d}], [10, 6, 3, 2]                                      
[{}, {a}, {b}, {a, b}, {c}, {a, c}, {d}, {b, c}, {a, d}, {a, b, c}, {b, d}, {a, b, d}, {c, d}, {a, c, d}, {b, c, d}, {a, b, c, d}], [10, 7, 4, 2]                                      
[{}, {a}, {b}, {a, b}, {c}, {a, c}, {d}, {a, d}, {b, c}, {a, b, c}, {b, d}, {a, b, d}, {c, d}, {a, c, d}, {b, c, d}, {a, b, c, d}], [8, 6, 4, 1]                                       
[{}, {a}, {b}, {a, b}, {c}, {d}, {a, c}, {b, c}, {a, d}, {b, d}, {a, b, c}, {a, b, d}, {c, d}, {a, c, d}, {b, c, d}, {a, b, c, d}], [10, 8, 4, 3]                                      
[{}, {a}, {b}, {a, b}, {c}, {d}, {a, c}, {a, d}, {b, c}, {b, d}, {a, b, c}, {a, b, d}, {c, d}, {a, c, d}, {b, c, d}, {a, b, c, d}], [8, 7, 4, 2]                                       
[{}, {a}, {b}, {c}, {a, b}, {a, c}, {b, c}, {a, b, c}, {d}, {a, d}, {b, d}, {c, d}, {a, b, d}, {a, c, d}, {b, c, d}, {a, b, c, d}], [10, 4, 3, 2]                                      
[{}, {a}, {b}, {c}, {a, b}, {a, c}, {b, c}, {d}, {a, b, c}, {a, d}, {b, d}, {c, d}, {a, b, d}, {a, c, d}, {b, c, d}, {a, b, c, d}], [8, 4, 3, 2]                                       
[{}, {a}, {b}, {c}, {a, b}, {a, c}, {d}, {b, c}, {a, d}, {a, b, c}, {b, d}, {c, d}, {a, b, d}, {a, c, d}, {b, c, d}, {a, b, c, d}], [8, 5, 4, 2]                                       
[{}, {a}, {b}, {c}, {a, b}, {a, c}, {d}, {a, d}, {b, c}, {a, b, c}, {b, d}, {c, d}, {a, b, d}, {a, c, d}, {b, c, d}, {a, b, c, d}], [10, 7, 6, 2]                                      
[{}, {a}, {b}, {c}, {a, b}, {d}, {a, c}, {b, c}, {a, d}, {b, d}, {a, b, c}, {c, d}, {a, b, d}, {a, c, d}, {b, c, d}, {a, b, c, d}], [8, 6, 4, 3]                                       
[{}, {a}, {b}, {c}, {a, b}, {d}, {a, c}, {a, d}, {b, c}, {b, d}, {a, b, c}, {c, d}, {a, b, d}, {a, c, d}, {b, c, d}, {a, b, c, d}], [10, 8, 6, 3]                                      
[{}, {a}, {b}, {c}, {d}, {a, b}, {a, c}, {b, c}, {a, d}, {b, d}, {c, d}, {a, b, c}, {a, b, d}, {a, c, d}, {b, c, d}, {a, b, c, d}], [8, 6, 5, 4]                                       
[{}, {a}, {b}, {c}, {d}, {a, b}, {a, c}, {a, d}, {b, c}, {b, d}, {c, d}, {a, b, c}, {a, b, d}, {a, c, d}, {b, c, d}, {a, b, c, d}], [7, 6, 5, 3]

Следующее не является правильным абстрактным порядком:

{}, {a}, {b}, {c}, {d}, {a,b}, {e}, {a,c}, {b,c}, {a,d}, {a,e}, {b,d}, {b,e}, {c,d}, {a,b,c}, {a,b,d}, {c,e}, {d,e}, {a,b,e}, {a,c,d}, {a,c,e}, {b,c,d}, {b,c,e}, {a,d,e}, {b,d,e}, {a,b,c,d}, {c,d,e}, {a,b,c,e}, {a,b,d,e}, {a,c,d,e}, {b,c,d,e}, {a,b,c,d,e}

Этот порядок подразумевает, что:

d < a + b
b + c < a + d
a + e < b + d
a + b + d < c + e

Суммирование этих неравенств дает:

2a + 2b + c + 2d + e < 2a + 2b + c + 2d + e

что противоречие. Ваш код не должен учитывать этот порядок. Такие контрпримеры впервые появляются в n=5. Пример из этой статьи , пример 2.5 на стр. 3.

Этот порядок является недействительным, несмотря на тот факт, что это A < Bозначает, что A U C < B U Cдля любого Cнепересекающегося от Aи B.


Ваш код или программа должны быть достаточно быстрыми, чтобы вы могли выполнить их до завершения n=4перед отправкой.

Представления могут быть программами, функциями и т. Д. Как обычно.

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


Давно не виделись Исаака!
orlp

п,QпQпQпп,QQ(пQ)aбс...

пп,QQ(пQ){a,с},{б,с}

@orlp Хорошо вернуться! Я думаю, что я буду делать в основном вопросы в обозримом будущем
Исаак

Не могли бы вы также добавить 14 возможных заказов для n = 4?
Питер Тейлор

Ответы:


11

Python 3 + SciPy, 396 390 385 351 336 355 байт

from scipy.optimize import*
n=int(input())
r=range(n)
def f(u):
 s=linprog(r,u,[-n]*len(u),options={'tol':.1});c=s.success;y=sorted(range(c<<n),key=lambda a:s.x.round()@[a>>i&1for i in r])
 for a,b in zip(y,y[1:]):
  v=[(a>>i&1)-(b>>i&1)for i in r]
  if~-(v in u):c+=f(u+[[-z for z in v]]);u+=v,
 return+c
print(f([[(i==j-1)-(i==j)for i in r]for j in r]))

Попробуйте онлайн!

Это теперь работает в течение 5 секунд при n = 5. if~-(v in u):Может быть удалена для -18 байт , но огромный штраф производительности.

Если вы хотите напечатать все абстрактные упорядочения по мере их обнаружения, а не просто считать их, добавьте if c:print(s.x.round(),y)перед forциклом. (Подмножества представлены двоичными целыми числами, где каждый бит соответствует наличию или отсутствию одного элемента: { a , c , d } ₂ 1101₂ = 13.)

Как это работает

fрекурсивно считает абстрактные упорядочения, удовлетворяющие заданному списку ограничений. Начнем с ограничений na , a + nb , b + nc , c + nd . Используя линейное программирование, мы находим решение для ограничений (или возвращаем 0, если его нет) - в этом случае мы получаем a = 4, b = 8, c = 12, d = 16. Округляем решение до целых чисел , затем вычислите порядок ссылок, отсортировав все его подмножества по их сумме:

{ a }, { b }, { c }, { a , b }, { d }, { a , c }, { a , d }, { b , c }, { b , d }, { a , b , c }, { c , d }, { a , b , d }, { a , c , d }, { b , c , d }, {a , b , c , d }

Округление не может привести к нарушению каких-либо ограничений более чем на n / 2, поэтому мы добавили поле n .

Поскольку Python sortedстабильны, любые связи между подмножествами разрываются в том же обратном лексикографическом порядке, в котором мы их сгенерировали. Таким образом, мы могли бы представить замену { a , b , c , d } на { a · 2 ^ n + 2 ^ 0, b · 2 ^ n + 2 ^ 1, c · 2 ^ n + 2 ^ 2, d · 2 ^ n + 2 ^ 3}, чтобы получить тот же порядок без каких-либо связей.

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

Либо { a }> { b },
либо { a } <{ b }> { c },
либо { a } <{ b } <{ c }> { a , b },
либо { a } <{ b } < { c } <{ a , b }> { d },

В каждом случае мы добавляем эти новые ограничения с полем n и рекурсивно вызываем fс добавлением новых ограничений.

Заметки

Некоторое время я предполагал (но не предполагал), что линейные программные решения с полем 1 в ограничениях всегда будут целыми числами. Это оказывается ложным: контрпример с n = 7 равен {2,5, 30, 62,5, 73,5, 82, 87,5, 99,5}.

Python, 606 байт (быстрее, без внешних библиотек)

n=int(input())
r=range(n)
e=enumerate
def l(u,x):
 for i,v in e(u):
  for j,a in e(v):
   if a<0:break
  else:return[0]*len(x)
  if sum(b*x[k]for k,b in e(v))>0:
   x=l([[b*w[j]-a*w[k]for k,b in e(v)if k!=j]for w in u[:i]],x[:j]+x[j+1:]);x.insert(j,0)
   for k,b in e(v):
    if k!=j:x[j]+=b*x[k];x[k]*=-a
 return x
def f(u,x):
 x=l(u,x);c=any(x);y=sorted(range(c<<n),key=lambda a:sum(x[i]*(a>>i&1)for i in r))
 for a,b in zip(y,y[1:]):
  v=[(a>>i&1)-(b>>i&1)for i in r]+[1]
  if~-(v in u):c+=f(u+[[-z for z in v[:-1]]+[1]],x);u+=v,
 return+c
print(f([[(i==j-1)-(i==j)for i in r]+[1]for j in r],[1]*(n+1)))

Попробуйте онлайн!

Это выполняется для n = 5 за четверть секунды и n = 6 через 230 секунд (75 секунд в PyPy).

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



@ Mr.Xcoder Конечно, спасибо!
Андерс Касеорг

@ Линн Спасибо! Я немного
пошла на

1
@AlonAmit Похоже, что это заняло около 55 минут для n = 6. SciPy не лучший на LP; У меня есть версия, использующая GLPK вместо SciPy, которая делает n = 6 за 70 секунд. Что еще более важно, версия SciPy получила неправильный ответ (и GLPK правильный) ... ну, это ... интересно ... Интересно, это SciPy # 6690 ?
Андерс Касеорг

1
@AlonAmit # 6690 не так ли? Но я добавил options={'tol':.1}, что, кажется, решить проблему.
Андерс Касеорг

0

Ruby, 308 байт, намного быстрее

Запускает случай 4 в ~ 150мс. Специализированная библиотека не используется.

->n{t=2**(n-1)
n==0 ?[[0]]:P[n-1].map{|a|b=a.map{|i|i+t}
[*0..t].repeated_combination(t).select{|m|m[0]>=a.index(n-1)}.map{|m|c,d=a.dup,b.dup;m.reverse.map{|i|c.insert(i,d.pop)};c}}.flatten(1).select{|p|p.combination(2).all?{|(x,y)|x&~y==0||y&~x!=0&&n.times.all?{|i|x!=y<<i+1}&&p.index(x&~y)<p.index(y&~x)}}}

Это рекурсивно перемежающийся результат незначительного случая, например

[{}, {a}, {b}, {c}, {a, b}, {a, c}, {b, c}, {a, b, c}]

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

Часть, которая проверяет на соответствие, та же, что и раньше, но не комбинации для тестирования намного меньше.

Расширенная и прокомментированная версия:

->n{
    t=2**(n-1)
    if n==0
        [[0]]
    else
        # for each one of the previous nice orderings
        P[n-1].map { |a|
            # create the missing sets, keep order
            b = a.map{|i|i+t}
            # intersperse the two sets
            [*0..t].repeated_combination(t) # select t insertion points
                .select do |m|
                    # ensure the new singleton is after the old ones
                    m[0] >= a.index(n-1)
                end
                .map do |m|
                    # do the interspersion
                    c,d=a.dup,b.dup
                    m.reverse.map{|i|c.insert(i, d.pop)}
                    c
                end
        }.flatten(1).select{ |p|
            # check if the final ordering is still nice
            p.combination(2).all? { |(x,y)|
                (x&~y==0) || 
                (y&~x!=0) && 
                n.times.all?{|i|x!=y<<i+1} && 
                (p.index(x&~y)<p.index(y&~x))
            }
        }
    end
}

Ruby, 151 байт, довольно медленно

(случай трех элементов занимает << 1s, случай четырех все еще работает)

->n{[*1...2**n-1].permutation.select{|p|p.combination(2).all?{|(x,y)|x&~y==0||y&~x!=0&&n.times.all?{|i|x!=y<<i+1}&&p.index(x&~y)<p.index(y&~x)}}.count}

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

отформатирован:

-> n {
  [*1...2**n-1]. # prepare permutations of non-empty and non-full sets
    permutation.
    select { |p|
      p.combination(2). # check all ordered pairs
        all? { |(x, y)|
          # first is subset of second 
          x &~ y == 0 ||
          # second is not subset of first
          y &~ x != 0 &&
          # first is not a right shift of second
          # (this normalizes the ordering on atoms)
          n.times.all? { |i| x != y << i+1 } &&
          # after taking out common elements, ordering agrees 
          p.index(x &~ y) < p.index(y &~ x)
        }
    }.
    count
}

Я не могу проверить это выше 3 на моей машине, но это (139 байт) должно быть функционально идентично вашему решению. Изменения: ...x-1=> ..x-2, .select{...}.count=> .count{...}, |(x,y)|=> |x,y|, x&~y==0||y&~x!=0=> x&~y<1||y&~x>0так как a&~bне может быть отрицательным, если я не ошибаюсь
Asone Tuhid

1
Посмотрите на n=5контрпример, который я только что добавил. Если я не ошибаюсь, ваш код примет это.
Исаак

2
Ссылка TIO, показывающая, что она не работает правильно на контрпримере: попробуйте онлайн!
Исаак

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

1
Для более быстрого решения: 280 байт Попробуйте онлайн! , Обратите внимание, что вы должны включить имя рекурсивной функции ( P=). Кроме того, я думаю, что вы должны вернуть номер, так что вам, возможно, придется включить .sizeтуда где-нибудь.
Asone Tuhid
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.