Subset Sum Siparişleri


22

Bir npozitif sayılar 2^nkümesi alt kümelere sahiptir . Bu alt grupların hiçbiri aynı toplamı yoksa, "iyi" bir küme olarak adlandırırız. {2, 4, 5, 8}böyle güzel bir set. Alt kümelerden hiçbiri aynı toplamda olmadığından, alt kümeleri toplama göre sıralayabiliriz:

[{}, {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}]

Numaraları artan sırayla [2, 4, 5, 8]sembollerle etiketlersek [a, b, c, d], aşağıdaki soyut sıralamayı alırız:

[{}, {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}]

Başka bir güzel pozitif sayı kümesi, aynı soyut sıralamaya veya farklı bir numaraya sahip olabilir. Örneğin, [3, 4, 8, 10]farklı bir soyut sıraya sahip hoş bir set:

[{}, {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}]

Bu zorlukla, güzel npozitif sayılar kümelerinin farklı soyut sıralarını saymalısınız. Bu dizi OEIS A009997'dir ve başlangıçta bilinen bilinen değerler n=1şunlardır:

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

Örneğin n=3, aşağıdakiler iki olası soyut düzendir:

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

Çünkü n=4, aşağıdaki 14 olası soyut emir, artı bu emir ile güzel bir örnek:

[{}, {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şağıdaki, geçerli bir soyut sipariş değildir:

{}, {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}

Bu sipariş şu anlama gelir:

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

Bu eşitsizliklerin toplanması şunları verir:

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

bu bir çelişkidir. Kodunuz bu siparişi saymamalıdır. Bu tür karşı örnekler ilk önce görünür n=5. Örnek Bu çalışmada , sayfa 3, örneğin 2.5.

Bu sıralama, A < Bkendisinden ve arasındaki A U C < B U Cherhangi bir Cayrılık için, bunun ima edilmesine rağmen geçersizdir .AB


Kodunuz veya programınız n=4göndermeden önce üzerinde çalışmasını sağlayacak kadar hızlı olmalıdır .

Gönderimler her zamanki gibi programlar, işlevler vb. Olabilir.

Her zaman olduğu gibi Standart Loopholes yasaktır. Bu kod golf, bayt cinsinden en kısa cevap kazanıyor. Yorumlarda açıklayıcı sorular sormaktan çekinmeyin.


Uzun zamandır görüşemedik isaac!
orlp

Zaman , iki alt kümesi olan, herhangi bir senaryo vardır dışında herhangi bir bilgi çıkarsanabilir veya değil, sayım ilk ? P Q P Q p P , q Q ( p q ) a b c P,QPQPQpP,qQ(pq)birbc...
orlp

Cevap: evet. yeterince sıkı değil, örnek: . { a , c } , { b , c }pP,qS(pq){bir,c},{b,c}
orlp

@ orlp Geri dönmek güzel! Sanırım öngörülebilir geleceğe yönelik daha çok soru soracağım
isaacg

N = 4 için 14 olası siparişi de ekleyebilir misiniz?
Peter Taylor

Yanıtlar:


11

Python 3 + SciPy, 396 390 385 351 336 355 bayt

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]))

Çevrimiçi deneyin!

Bu şimdi n = 5 için yaklaşık 5 saniyede çalışıyor. if~-(v in u):-18 bayt ama büyük bir performans cezası kaldırılabilir.

Tüm soyut sıraları, yalnızca saymak yerine, bulundukları şekilde yazdırmak istiyorsanız if c:print(s.x.round(),y), fordöngüden önce ekleyin . ( Alt kümeler , her bitin bir öğenin varlığına veya yokluğuna karşılık geldiği ikili tam sayılarla gösterilir: { a , c , d } ↔ 1101₂ = 13.)

Nasıl çalışır

fbelirli bir kısıtlama listesini karşılayan soyut siparişleri tekrar tekrar sayar. Bu kısıtlamalar ile başlar na , bir + nb , b + nC , c + nd . Doğrusal programlama kullanarak, kısıtlamalara bir çözüm buluruz (veya yoksa 0 döndürür) - bu durumda a = 4, b = 8, c = 12, d = 16 alırız . , ardından tüm alt kümelerini toplamlarına göre sıralayarak bir referans siparişi hesaplayın:

{ 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 }

Yuvarlama hiçbir kısıtlamanın n / 2'den daha fazla ihlal edilmesine neden olamaz , bu yüzden n marjı ekledik .

Python'un sortedkararlı olması nedeniyle, alt-kümeler arasındaki bağlar, onları ürettiğimiz aynı ters-sözlük sırasına göre kopar. Böylece { a , b , c , d } yerine { a · 2 ^ n + 2 ^ 0, b · 2 ^ n + 2 ^ 1, c · 2 ^ n + 2 ^ 2, d · 2 ^ ile değiştirmeyi hayal edebildik. n + 2 ^ 3} aynı sıralamayı hiçbir bağ olmadan elde etmek için.

Plan, diğer tüm soyut siparişleri , referans siparişine ilk olarak katılmadıkları yere göre durum analizine göre kategorilere ayırmak :

{ A }> { b }
veya { a } <{ b }> { c }
veya { a } <{ b } <{ c }> { a , b }
veya { a } <{ b } < { c } <{ a , b }> { d },

Her durumda, bu yeni kısıtlamaları n boşluğu ile ekliyoruz ve tekrarlı olarak feklenen yeni kısıtlamaları çağırıyoruz .

notlar

Bir süredir, sınırlardaki marjı 1 olan doğrusal program çözümlerinin her zaman tamsayı olacağını varsaymıştım (ancak varsaymıyorum). Bu yanlış olduğu ortaya çıkıyor: n = 7 olan bir karşı örnek {2.5, 30, 62.5, 73.5, 82, 87.5, 99.5}.

Python, 606 bayt (daha hızlı, harici kitaplık yok)

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)))

Çevrimiçi deneyin!

Bu için çalışır n saniyenin dörtte = 5, ve n = 6 230 saniye (PYPY 75 saniye).

Kayan nokta yuvarlama sorunlarını önlemek için homojen koordinatlarda tamsayı matematiğini kullanan elle kodlanmış bir doğrusal programlama çözücü içerir.



@ Mr.Xcoder Tabii, teşekkürler!
Anders Kaseorg

@Lynn Teşekkürler! Biraz
uzağım

1
@AlonAmit N = 6 için yaklaşık 55 dakika sürüyor gibi görünüyor. SciPy LP'de en iyisi değil; 70 saniyede n = 6 olan SciPy yerine GLPK kullanan bir sürümüm var. Daha ilginci, SciPy sürümü yanlış bir cevap aldı (ve doğru olanı GLPK)… yani, bu… ilginç… Acaba bu SciPy # 6690 mı?
Anders Kaseorg

1
@AlonAmit # 6690 değil mi? Ama ben options={'tol':.1}de sorunla ilgileniyor gibi gözüktüm.
Anders Kaseorg

0

Ruby, 308 bayt, çok daha hızlı

Durum 4'ü ~ 150ms'de çalıştırır. Özel bir kütüphane kullanılmaz.

->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)}}}

Örneğin küçük bir davanın özyinelemeli yayılma sonucu

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

ek bir eleman eklenmiş karşılık gelen alt kümelerle - aynı göreceli sırayı tutmaları gerekir. Ayrıca, yeni singleton'ın önceki tüm singletonlardan sonra eklenmesini sağlar.

Uygunluk kontrolü yapan kısım önceki ile aynıdır ancak test edilecek kombinasyonlar çok daha az değildir.

Genişletilmiş ve yorumlanan sürüm:

->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 bayt, oldukça yavaş

(üç elementin durumu << 1s alır, dörtün durumu hala devam ediyor)

->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}

Altkümelerin bitfield gösterimi üzerinde çalışır, bu nedenle altkümelerin kendilerini göstermesi gerektiğinde çıktının masaj yapılması gerekebilir.

biçimlendirilmiş:

-> 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
}

Makinemde 3'ün üzerinde test edemiyorum, ancak bunun (139 byte) işlevsel olarak sizin çözümünüzle aynı olması gerekir. Değişiklikler: ...x-1=> ..x-2, .select{...}.count=> .count{...}, |(x,y)|=> |x,y|, x&~y==0||y&~x!=0=> x&~y<1||y&~x>0beri a&~byanılmıyorsam eğer negatif olamaz
Asone TÜHİD

1
n=5Yeni eklediğim karşı örneğe bak . Yanılmıyorsam, kodunuz kabul eder.
isaacg

2
Bunu gösteren TIO linki karşı örnek üzerinde düzgün çalışmıyor: Çevrimiçi deneyin!
isaacg

1
Yeni sürümünüz denilen özyinelemeli bir işlev gibi görünüyor P, bu nedenle adsız olamaz. Ayrıca, gönderdiğim karşı örnek nedeniyle yine de başarısız olduğunu düşünüyorum.
isaacg

1
Daha hızlı çözüm için: 280 bayt Çevrimiçi deneyin! . Özyinelemeli bir işlevin adını ( P=) eklemeniz gerektiğini unutmayın . Ayrıca, bir numarayı geri vermeniz gerektiğini düşünüyorum, o yüzden bir .sizeyere dahil etmek zorunda kalabilirsiniz .
Asone Tuhid
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.