サブセット和順序


22

n正数のセットには2^nサブセットがあります。これらのサブセットが同じ合計を持たない場合、セットを「nice」と呼びます。{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次の2つの抽象順序が可能です。

[{}, {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ます。このペーパーの例、3ページの例2.5

この順序付けは、およびからの不整合A < BについてA U C < B U C、を意味するという事実にもかかわらず無効です。CAB


コードまたはプログラムは、n=4送信する前に完了するまで実行できるほど高速でなければなりません。

提出物は、通常のプログラム、機能などです。

いつものように、標準の抜け穴は禁止されています。これはコードゴルフであるため、バイト単位の最短回答が優先されます。コメントで明確な質問をしてください。


久しぶりのアイザック!
orlp

場合 2つのサブセットであり、任意のシナリオが存在するP Qが以外の情報から推定することができるP Q又はP P Q Q P Q 、初期カウントしないA BはC ...PQPQPQpPqQpqabc
orlp

pPqQpq{ac}{bc}

@orlp戻ってきてよかった!私は主に予見可能な未来のための質問をしていると思います
-isaacg

n = 4の14の可能な順序も追加できますか?
ピーターテイラー

回答:


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ループの前に追加します。(サブセットは、各ビットが1つの要素の有無に対応する2進整数で表されます:{ acd } 11101₂=13。)

使い方

f制約の特定のリストを満たす抽象順序を再帰的にカウントします。私たちは、制約で始まるN ≤ 、+ NBB + NCC + ND。線形計画法を使用することで、我々は、制約の解決策を見つける(または1つが存在しない場合は0を返す)我々が得るこの場合-in = 4、B = 8、C = 12、D = 16我々は、整数への解決策を丸めます、その合計ですべてのサブセットをソートすることにより、参照順序を計算します:

{ a }、{ b }、{ c }、{ ab }、{ d }、{ ac }、{ ad }、{ bc }、{ bd }、{ abc }、{ cd }、{ abd }、{ acd }、{ bcd }、{abcd }

丸めにより、制約がn / 2を超えて違反することはありません。これが、nのマージンを追加した理由です。

Python sortedは安定しているため、サブセット間の関係は、生成したのと同じ逆辞書式順序で壊れます。したがって、{ abcd }を{ 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 }> { ab }
または{ a } <{ b } < { c } <{ ab }> { d }、

各ケース内で、これらの新しい制約をマージンnf追加し、新しい制約を追加して再帰的に呼び出します。

ノート

しばらくの間、制約にマージン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の秒(PyPyで75秒)。

浮動小数点の丸めの問題を回避するために、同次座標で整数演算を使用する手動コーディングの線形プログラミングソルバーが含まれています。



@ Mr.Xcoder確かに、ありがとう!
アンデルスカセオルグ

@Lynnありがとう!私はそれを遅くしたくないので、私はあまり、それがすでにnの約3分かかりビットを損なわ= 5
アンダースKaseorg

1
@AlonAmit n = 6の場合、約55分かかったようです。SciPyはLPでは最高ではありません。SciPyの代わりにGLPKを使用して、70秒でn = 6を実行するバージョンがあります。もっと心配なことに、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バイト、かなり遅い

(3つの要素の場合は<< 1秒かかり、4つの場合はまだ実行中です)

->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、どこかに組み込む必要があるかもしれません。
アソーントゥヒッド
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.