Замовлення підмножини


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перш ніж надсилати його.

Подання можуть бути програмами, функціями тощо.

Стандартні лазівки , як завжди, заборонені. Це кодовий гольф, тому найкоротша відповідь у байтах виграє. Сміливо задайте уточнюючі питання в коментарях.


Давно не бачимо isaac!
orlp

P,QPQPQpP,qQ(pq)abc

pP,qQ(pq){a,c},{b,c}

@orlp Добре повернутися! Я думаю, що я буду займатися здебільшого питаннями в осяжному майбутньому
isaacg

Чи можете ви також додати 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]))

Спробуйте в Інтернеті!

Тепер це працює протягом n = 5 приблизно за 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's 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 Звичайно, дякую!
Андерс Касеорг

@Lynn Дякую! Я трохи пішов на компроміс, тому що не хочу занадто сповільнювати його - це вже займає майже 3 хвилини для n = 5.
Anders Kaseorg

1
@AlonAmit Схоже, що на n = 6. минуло 55 хвилин, SciPy - не найкращий на LP; У мене версія, що використовує GLPK замість SciPy, яка робить n = 6 за 70 секунд. Що ще більше стосується, що версія SciPy отримала неправильну відповідь (і GLPK правильну)… так що, це… цікаво… Цікаво, чи це SciPy # 6690 ?
Андерс Касеорг

1
@AlonAmit # 6690 чи не так. Але я додав options={'tol':.1}, що, здається, опікується проблемою.
Anders Kaseorg

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
}

Рубін, 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контрприклад, який я щойно додав. Якщо я не помиляюся, ваш код прийме його.
isaacg

2
Посилання TIO, яке показує, що воно не працює належним чином на контрприкладі: спробуйте в Інтернеті!
isaacg

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

1
Для швидшого рішення: 280 байт Спробуйте в Інтернеті! . Зауважте, що ви повинні вказати ім'я рекурсивної функції ( P=). Крім того, я думаю, що вам потрібно повернути номер, щоб вам довелося .sizeдесь там увійти.
Асона Тухід
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.