和のセットに適合する配列を見つける


17

A長さの配列を考えnます。配列には正の整数のみが含まれます。たとえばA = (1,1,2,2)f(A)のすべての空でない隣接部分配列の合計のセットとして定義しましょうA。この場合f(A) = {1,2,3,4,5,6}。作成する手順f(A) は次のとおりです。

の部分配列はAです(1), (1), (2), (2), (1,1), (1,2), (2,2), (1,1,2), (1,2,2), (1,1,2,2)。それぞれの合計は1,1,2,2,2,3,4,4,5,6です。したがって、このリストから取得するセットはです{1,2,3,4,5,6}

仕事

S正の整数と配列の長さのみを含むソートされた順序で指定された合計のセットが与えられたn場合、あなたのタスクは、少なくとも1つの配列を出力するXことf(X) = Sです。

例えば、場合S = {1,2,3,5,6}n = 3、有効な出力がありますX = (1,2,3)

そのような配列がない場合X、コードは定数値を出力する必要があります。

入力:n=4, S = (1, 3, 4, 5, 6, 8, 9, 10, 13)、可能な出力:X = (3, 5, 1, 4)

入力:n=6, S = (2, 3, 4, 5, 7, 8, 9, 10, 12, 14, 17, 22)、可能な出力:X = (5, 3, 2, 2, 5, 5)

入力:n=6, S = (2, 4, 6, 8, 10, 12, 16)、可能な出力:X = (4, 2, 2, 2, 2, 4)

入力:n=6, S = (1, 2, 3, 4, 6, 7, 8, 10, 14)、可能な出力:X = (4, 2, 1, 1, 2, 4)

入力:n=10, S = (1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 14, 15, 16, 17, 18, 19, 20, 23, 24, 25)、可能な出力:X = (1, 1, 3, 1, 2, 1, 2, 5, 4, 5)

入力:n=15, S = (1, 2, 3, 4, 6, 7, 8, 9, 10, 11, 13, 14, 15, 16, 17, 18, 20, 21, 22, 23, 24, 25, 26, 27, 28, 30, 31)、可能な出力:X = (1, 2, 1, 3, 3, 1, 3, 3, 1, 3, 3, 1, 2, 1, 3)

入出力形式

あなたのコードは入力を受け取り、あなたが便利だと思うどんな人間が読みやすい形式でも出力を与えることができます。ただし、質問の例でテストの出力を示してください。

実行時間

問題のすべての例について、コードを最後まで実行できる必要があります。これは、原則的にのために正しいはずですnまで15しかし、あなたはそれがすべての入力のために十分な速さになることを証明する必要はありません。


コメントは詳細なディスカッション用ではありません。この会話はチャットに移動さました
デニス

おそらく2桁の数字のテストケースが必要です。
魔法のタコ

回答:


6

、20バイト

ḟȯ⁰¦ṁ∫ṫ!¡Sof~Λ€∫×:¹g

オンラインでお試しください!

1つのソリューション、または存在しない場合は空のリストを返します。最後のテストケース(n=15)は、TIOで3.8秒で終了します。

説明

プログラムには2つの部分があります。最初の部分(¡およびその右側)では、スライスの合計がであるkすべての長さkリストを含むリストであるth要素を持つ無限リストを構築しSます。これを帰納的に行い、の1要素のスライスから開始し、S各ステップで各要素Sを各リストの先頭に追加し、プレフィックスの合計がである要素を保持しSます。2番目の部分(!およびその左側)で、n長さnリストを含むリストのth要素を取得します。これらのうち、スライスの合計に実際にのすべての要素が含まれる最初のものを選択しますS

コードでは、わかりやすくするためにo、最初にandをȯ(2つおよび3つの関数を1つに構成する)括弧で置き換えましょう。

¡S(f~Λ€∫)×:¹g  First part. Input is a list, say S=[1,2,3]
            g  Group equal adjacent elements: [[1],[2],[3]]
¡              Iterate function:
                Argument is a list of lists, say [[1,1],[1,2],[2,1]]
         ×      Mix (combine two lists in all possible ways)
          :     by prepending
           ¹    with the list S: [[1,1,1],[1,1,2],[2,1,1],[1,2,1],[2,1,2],[3,1,1],[2,2,1],[3,1,2],[3,2,1]]
   f            Filter by condition:
        ∫        Cumulative sums: [[1,2,3],[1,2,4],[2,3,4],[1,3,4],[2,3,5],[3,4,5],[2,4,5],[3,4,6],[3,5,6]]
     ~Λ          All of the numbers
 S     €         are elements of S: [[1,1,1]]
                 Only this list remains, since the other cumulative sums contain numbers not from S.
               Result of iteration: [[[1],[2],[3]],[[1,1],[1,2],[2,1]],[[1,1,1]],[],[],[]...

ḟ(⁰¦ṁ∫ṫ)!      Second part. Implicit input, say n=2.
        !      Take nth element of above list: [[1,1],[1,2],[2,1]]
ḟ              Find first element that satisfies this:
                Argument is a list, say [1,2]
      ṫ         Tails: [[1,2],[2]]
    ṁ           Map and concatenate
     ∫          cumulative sums: [1,3,2]
 ȯ ¦            Does it contain all elements of
  ⁰             S? Yes.
               Result is [1,2], print implicitly.

さらに説明が必要な部分があります。このプログラムでは、上付き文字は⁰¹両方とも最初の引数を参照していますS。ただし、α関数は、その後α¹「適用を意味αするS一方、」⁰α手段「プラグSの第2引数にα」。この関数¦は、最初の引数に2番目の要素(多重度をカウント)のすべての要素が含まれているかどうかを確認しSます。

最初の部分では、¡使用する関数はとして解釈できますS(f~Λ€∫)(×:)¹。コンビネータSは次のようSαβγ -> (αγ)(βγ)に動作し(f~Λ€∫¹)(×:¹)ます。つまり、これを単純化できます。2番目の部分は×:¹、「Sプリペンドによる混合」であり、その結果は最初の部分に渡されます。最初の部分はf~Λ€∫¹、このように機能します。この関数はf、条件(この場合は)でリストをフィルターします~Λ€∫¹。リストのリストを受け取るLので、持ってい~Λ€∫¹Lます。コンビネータ~は次のように動作し~αβγδε -> α(βδ)(γε)ます。最初の引数が渡されβ、2番目の引数が渡され、γ結果がと結合されαます。これは我々が持っていることを意味しますΛ(€¹)(∫L)。最後の部分は、∫Lちょうど累積和ですL€¹は、のメンバーシップをチェックしSΛ条件(ここ€¹)とリスト(ここ∫L)を取り、すべての要素がそれを満たしていることをチェックする関数です。簡単に言えば、累積和がすべてであるかどうかでミキシングの結果をフィルタリングしますS


説明を楽しみにしています!
アヌーシュ

1
@Anushコードの内訳を追加しました。
ズガーブ

私はこのソリューションが本当に好きです。それは一種の美しいです。
アヌーシュ

6

ルビー、135バイト

->a,n{r=w=1;r+=1until w=(s=a[0,r]).product(*[s]*~-n).find{|x|x.sum==a.max&&a==[]|(1..n).flat_map{|r|x.each_cons(r).map(&:sum)}.sort};w}

オンラインでお試しください!

幅優先検索を使用します。n = 10はTIOで動作し、n = 15は1分以上かかりますが、私のマシンでは動作します。

ルビー、147バイト

->a,n{r=w=1;r+=1until w=([a[-1]-a[-2]]).product(*[s=a[0,r]]*~-n).find{|x|x.sum==a.max&&a==[]|(1..n).flat_map{|r|x.each_cons(r).map(&:sum)}.sort};w}

オンラインでお試しください!

最適化されたバージョン、n = 15(〜20秒)TIOで動作

実際、これが非総当たりアプローチの始まりです。誰かがそれに取り組み、完全な解決策を見つけることを願っています。

最初のアイデア:

  • 出力配列の合計は、入力配列の最後の要素(最大)です。
  • 出力配列の合計から最初の(または最後の)要素を引いたものが、入力配列の最後から2番目の要素です。
  • 配列が解である場合、逆配列も解であるため、最初の要素は入力配列の最後の2つの要素の差であると想定できます。
  • 2番目の要素は、入力配列の2番目と3番目、または2番目と4番目の最後の要素の差です。

次の最適化に進みます。

ルビー、175バイト

->a,n{r=w=1;r+=1until w=([a[-1]-a[-2]]).product([a[-2]-a[-3],a[-2]-a[-4]],*[s=a[0,r]]*(n-2)).find{|x|x.sum==a.max&&a==[]|(1..n).flat_map{|r|x.each_cons(r).map(&:sum)}.sort};w}

オンラインでお試しください!

TIOで約8.5秒。悪くない...

...など(実装予定)


これはとてもいいですね!
アヌーシュ

新しい非強引なアルゴリズムに興奮しています。さらに多くの例をテストしたい場合は、質問の新しいセクションに追加できます。
アヌーシュ

2
@Anush実際には、まだ総当たり(指数時間)ですが、いくつかの(多項式因子)最適化があります。
user202729

私にとって、最初の要素(より小さな要素)は常に解決策であることを忘れています。したがって、1と最後(すべての合計)があります。最後の2番目と言いますが、これは明確ではありません...この方法で他のすべてを見つける方法は可能です
...-RosLuP

5

Haskell、117 111バイト

@nimiのおかげで6バイト節約されました!

f r i n s|n<1=[r|r==[]]|1<2=[y:z|y<-s,t<-[y:map(y+)i],all(`elem`s)t,z<-f[a|a<-r,all(a/=)t]t(n-1)s]
n&s=f s[]n s

オンラインでお試しください!

frSins

ときn(にgolfedゼロであるn<1)すべての値が見られている場合、我々はチェックして、リストには、準備ができなければなりません。そうでない場合は、空のリストを返して解決策がないことを示し、そうでない場合は、空のリストを含むシングルトンリストを返します。このリストには、選択した要素が追加されます。このケースは、追加の方程式で処理することもできます。

f [] _ 0 _=[[]]
f _ _ 0 _=[]

場合はnゼロではない、我々は返します

[y:z|y<-s,t<-[y:map(y+)i],all(`elem`s)t,z<-f[a|a<-r,all(a/=)t]t(n-1)s]
 ^1^ ^2^^ ^......3......^ ^.....4.....^ ^.............5.............^

これは(1)リストのリストで、最初の要素(2)が由来しs、残り(5)が再帰呼び出しから由来しsます。条件(4)はすべての新しい合計がにあるという条件の下です。新しい合計は(3)で計算されます。これtは、シングルトンリストから引き出されたもので、慣用的なHaskellの場合のgolfいゴルフハックですlet t=y:map(y+)i。再帰呼び出し(5)はr、新しい和の中に現れる要素のない古いセットを新しいセットとして取得しtます。

メイン関数&はヘルパー関数を呼び出して、まだすべての値を見る必要があること(r=s)と、まだ合計がないこと(i=[])を示します。

さらに7バイトの場合、最初の結果(存在する場合)のみを計算するように計算を制限できます。これは非常に高速で、2秒未満ですべてのテストケースを処理します。

オンラインでお試しください!(これは、古いバージョンの最初の結果のみのバリエーションです)


1
これは驚くほど速いです。アルゴリズムを説明できれば素晴らしいと思います。
アヌーシュ


私はこの問題の最速のコードバージョンを提起することを考えています。ポリタイムソリューションがあると思いますか?
アヌーシュ

@nimiありがとう!ああ、古き良きmap、私だけ試してみました<$>が、必要に応じて、余分な括弧こと... @Anush I多項式時間ソリューションの見当がつかない
クリスチャンのSievers

3

クリーン、177バイト

import StdEnv,Data.List
$s n=find(\a=sort(nub[sum t\\i<-inits a,t<-tails i|t>[]])==s)(?{#u\\u<-s|u<=(last s)-n}(last s)n)
?e s n|n>1=[[h:t]\\h<-:e|h<=s-n,t<- ?e(s-h)(n-1)]=[[s]]

オンラインでお試しください!

私のマシンではn=15テストケースに約40秒かかりますが、TIOではタイムアウトします。

クリーン、297バイト

import StdEnv,Data.List
$s n=find(\a=sort(nub[sum t\\i<-inits a,t<-tails i|t>[]])==s)(~[u\\u<-s|u<=(last s)-n](last s)n(reverse s))
~e s n a|n>4=let u=a!!0-a!!1 in[[u,h:t]\\h<-[a!!1-a!!2,a!!1-a!!3],t<- ?e(s-u-h)(n-2)]= ?e s n
?e s n|n>1=[[h:t]\\h<-e,t<- ?(takeWhile((>=)(s-n-h))e)(s-h)(n-1)]=[[s]]

オンラインでお試しください!

これには、GBによって行われた最適化と、私自身の最適化が含まれます。それらのいくつかはより一般的にできると思うので、それが終わったら説明を追加します。

私のマシンでは約10秒、TIOでは40秒かかります。


使用した最適化について詳しく説明してください。興味深い。
アヌーシュ

1
@Anush私は彼らと一緒に答えを編集します、@mention明日彼らが起きたら、残念ながら今日は時間がありません。
18年

3

Python 3、177バイト

from itertools import*
s,n=eval(input())
for[*t]in combinations(s[:-2],n-2):
  a=[*map(int.__sub__,t+s[-2:],[0,*t,s[-2]])];
  {sum(a[p//n:p%n+1])for p in range(n*n)}^{0,*s}or-print(a)

オンラインでお試しください!

(読者がコードをスクロールしなくても済むように、いくつかの改行/スペースが追加されました)

私のJelly回答の直接の移植版(いくつかの修正を加えたもの、以下の「注」セクションを参照)

ローカル実行結果:

[user202729@archlinux golf]$ printf '%s' "from itertools import*
s,n=eval(input())
for[*t]in combinations(s[:-2],n-2):a=[*map(int.__sub__,t+s[-2:],[0,*t,s[-2]])];{sum(a[p//n:p%n+1])for p in range(n*n)}^{0,*s}or-print(a)" > a.py
[user202729@archlinux golf]$ wc -c a.py
177 a.py
[user202729@archlinux golf]$ time python a.py<<<'([1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 14, 15, 16, 17, 18, 19, 20, 23, 24, 25], 10)' 2>/dev/null
[1, 4, 1, 1, 1, 1, 1, 7, 7, 1]

real    0m3.125s
user    0m3.119s
sys     0m0.004s
[user202729@archlinux golf]$ time python a.py<<<'([1, 2, 3, 4, 6, 7, 8, 9, 10, 11, 13, 14, 15, 16, 17, 18, 20, 21, 22, 23, 24, 25, 26, 27, 28, 30, 31], 15)' 2>/dev/null
[3, 1, 2, 1, 3, 3, 1, 3, 3, 1, 3, 3, 1, 2, 1]

real    11m36.093s
user    11m33.941s
sys     0m0.387s
[user202729@archlinux golf]$ 

それitertoolsは冗長であると聞きましたが、私の最良のcombinations実装はさらに冗長です:

c=lambda s,n,p:s and c(s[1:],n-1,p+s[:1])+c(s[1:],n,p)or[]if n else[p]

  • 除算/モジュロを使用すると、a[p//n:p%n+1]約2倍の時間がかかりますが、いくつかのバイトが節約されます。
  • これは、ゼリーの回答とは少し異なります。ゼリーの回答は逆方向に反復します。
  • combinationsイテレータを返すおかげで、これはよりメモリに優しいです。

2

ゼリー、35バイト

Ẇ§QṢ⁼³
;³ṫ-¤0;I
ṖṖœcƓ_2¤¹Ṫ©ÇѬƲ¿ṛ®Ç

オンラインでお試しください!

ローカルで実行:(n = 15は1 GB以上のRAMを必要とします)

aaa@DESKTOP-F0NL48D MINGW64 ~/jellylanguage (master)
$ time python scripts/jelly fu z '[1,2,3,4,5,6,7,8,9,10,11,12,14,15,16,17,18,19,20,23,24,25]'<<<10
[8, 6, 2, 1, 1, 1, 1, 3, 1, 1]
real    0m1.177s
user    0m0.000s
sys     0m0.015s

aaa@DESKTOP-F0NL48D MINGW64 ~/jellylanguage (master)
$ time python scripts/jelly fu z '[1, 2, 3, 4, 6, 7, 8, 9, 10, 11, 13, 14, 15, 16, 17, 18, 20, 21, 22, 23, 24, 25, 2
6, 27, 28, 30, 31]'<<<15
[3, 1, 2, 1, 3, 3, 1, 3, 3, 1, 3, 3, 1, 2, 1]
real    12m24.488s
user    0m0.000s
sys     0m0.015s

(実際には35バイト以上かかるUTF8エンコードバージョンを実行しましたが、結果はとにかく同じです)

このソリューションでは、短絡を使用して実行時間を短縮します。

短絡なしで、このコードはおおよそ |S|2n2×n36+n2ログn2 評価する操作 262152×1536+152ログ1525.79×109、ただし、PythonとJellyの非効率性のため、完了するには永遠に時間がかかります。短絡のおかげで、もっと早く終了できます。

説明

すべての空でないプレフィックスの合計が入力に存在し、それらが厳密に増加していることに注意してください。また、最大および2番目に大きい要素は接頭辞の合計であると想定できます。

したがって、すべての選択方法を検討できます n2 最初とは異なる要素 |S|2 要素( |S|2n2そのようなリスト)、要素を回復するために連続した差異を計算します; 次に、それが単純に有効かどうかを確認します(すべて取得n2部分配列、合計の計算、一意化。サブアレイの全長は約n36


未テスト(ただし、同一のパフォーマンスが必要です)

ゼリー、32バイト

Ṫ©ÑẆ§QṢ⁻³
;³ṫ-¤ŻI
ṖṖœcƓ_2¤¹Ñ¿ṛ®Ç

オンラインでお試しください!


より非効率的なバージョン(短絡なし):

ゼリー、27バイト

Ẇ§QṢ⁼³
ṖṖœcƓ_2¤µ;³ṫ-¤0;I)ÑƇ

オンラインでお試しください!

n = 15テストの場合、最大2GBのRAMが必要で、約37分後に終了しません。


Ẇ§はに置き換えることができますÄÐƤẎ。より効率的かもしれません。


1

APL(NARS)、chars 758、バイト1516

r←H w;i;k;a;m;j
   r←⊂,w⋄→0×⍳1≥k←↑⍴w⋄a←⍳k⋄j←i←1⋄r←⍬⋄→C
A: m←i⊃w⋄→B×⍳(i≠1)∧j=m⋄r←r,m,¨∇w[a∼i]⋄j←m
B: i+←1
C: →A×⍳i≤k

G←{H⍵[⍋⍵]}

r←a d w;i;j;k;b;c
   k←↑⍴w ⋄b←⍬⋄r←0 ⋄j←¯1
A: i←1⋄j+←1⋄→V×⍳(i+j)>k
B: →A×⍳(i+j)>k⋄c←+/w[i..(i+j)]⋄→0×⍳∼c∊a⋄→C×⍳c∊b⋄b←b,c
C: i+←1⋄→B
V: →0×⍳∼a⊆b
   r←1

r←a F w;k;j;b;m;i;q;x;y;c;ii;kk;v;l;l1;i1;v1
   w←w[⍋w]⋄r←a⍴w[1]⋄l←↑⍴w⋄k←w[l]⋄m←8⌊a-2⋄b←¯1+(11 1‼m)⋄j←2⋄i←1⋄x←↑⍴b⋄i1←0⋄v1←⍬
I: i1+←1⋄l1←w[l]-w[l-i1]⋄v1←v1,w[1+l-i1]-w[l-i1]⋄→I×⍳(l1=i1)∧l>i1⋄→B
E: r←,¯1⋄→0
F: i←1⋄q←((1+(a-2)-m)⍴0),(m⍴1),0⋄r+←q
A:   i+←1⋄j+←1⋄→E×⍳j>4000
B:   →F×⍳i>x⋄q←((1+(a-2)-m)⍴0),b[i;],0⋄q+←r⋄v←q[1..(a-1)]⋄→A×⍳0>k-y←+/v
   q[a]←k-y⋄→A×⍳l1<q[a]⋄→A×⍳∼q⊆w⋄→A×⍳∼l1∊q⋄→A×⍳∼v1⊆⍦q⋄c←G q∼⍦v1⋄ii←1⋄kk←↑⍴c⋄→D
C:   →Z×⍳w d v1,ii⊃c⋄ii+←1
D:   →C×⍳ii≤kk
   →A
Z: r←v1,ii⊃c

G xの関数G(H関数の助けを借りて)は、xのすべての順列を見つけます。xdyの関数dは、ブール値を返すエクササイズ配列xに続いてy配列が生成されるかどうかを調べます。x F yの関数Fは、長さxの配列rを返します。ydrはtrue(= 1)実装と同じくらい長いですが、テストですべてのケースを短時間で計算するのはこれです... n = 15の場合、20秒のみ実行されます...これは多くのソリューションを見つけられず、短い時間で1つのソリューションを返します(ようやくそうです)(異なる入力の探索テストではありません...) + 42 + 8 + 11 + 11 + 18 + 24 + 24 + 54 + 11 + 12 + 7 + 45 + 79 + 69 + 12 + 38 + 26 + 72 + 79 + 27 + 15 + 6 + 13(758)

  6 F (2, 3, 4, 5, 7, 8, 9, 10, 12, 14, 17, 22)
5 3 2 2 5 5 
  6 F (2, 4, 6, 8, 10, 12, 16)
4 2 2 2 2 4 
  6 F (1, 2, 3, 4, 6, 7, 8, 10, 14)
4 2 1 1 2 4 
  10 F (1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 14, 15, 16, 17, 18, 19, 20, 23, 24, 25)
1 1 3 1 2 3 5 1 3 5 
  15 F (1, 2, 3, 4, 6, 7, 8, 9, 10, 11, 13, 14, 15, 16, 17, 18, 20, 21, 22, 23, 24, 25, 26, 27, 28, 30, 31)
1 2 1 3 3 1 3 3 1 3 3 1 2 1 3 
  ww←(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 14, 15, 16, 17, 18, 19, 20, 23, 24, 25)
  ww≡dx 1 1 3 1 2 3 5 1 3 5 
1
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.