バブルを配置する


26

math.stackexchangeで尋ねられた質問からコピーされたチャレンジに注意してください。

最近、私は泡を吹く技術をかなり習得しました。最初は次のように泡を吹きます: ここに画像の説明を入力してください

しかし、その後、物事は奇妙になり始めました:

ここに画像の説明を入力してください

しばらくして、かなり奇妙な泡を吹いていました。

ここに画像の説明を入力してください

数百個、場合によっては数千個のそのような泡を吹き飛ばした後、私の額は次の質問で突然しわになりました。たとえば、n = 1の場合、配置は1つだけです。n = 2の場合、2つの配置があります。n = 3の場合、4つの配置があります。n = 4の場合、9つの配置があります。

4つのバブルの9つの配置を次に示します。
ここに画像の説明を入力してください ここに画像の説明を入力してください ここに画像の説明を入力してください ここに画像の説明を入力してください ここに画像の説明を入力してください ここに画像の説明を入力してください ここに画像の説明を入力してください ここに画像の説明を入力してください ここに画像の説明を入力してください

これらすべての素晴らしい泡を吹き飛ばした後、私は彼らとのアレンジメントを数える喜びをあなたと共有すべきだと決めました。あなたの仕事は次のとおりです。


ゴール

nバブルを配置できる方法の数を数えるプログラム、関数、または同様のものを作成します。


入力

n、泡の数。n> 0


出力

これらのバブルを配置できる方法の数。


受賞基準

あなたのコードの周りにバブルを吹き込むことができれば、本当にクールだろう。コードを小さくすればするほど簡単になります。したがって、最小バイト数でコードを作成した人がコンテストに勝ちます。


追加情報

OEIS


5
気泡が交差する可能性がある場合、それは未解決の問題でありn = 4の173のソリューションがあります。
-orlp

@orlp幸いなことに、これらのバブルは交差しません。
-TheNumberOne

1
ある0有効な入力?
マーティンエンダー

@ KenY-Nはい。下部にOEISリンクが既にあります
ローマグラーフ

おっとっと!削除愚かなコメント時間...
ケンYN

回答:


12

Python 2、92 87バイト

a=lambda n:n<2or sum((k%d<1)*d*a(d)*a(n-k)for k in range(1,n)for d in range(1,1+k))/~-n

平易な英語:計算するにa(n)は、以下のすべての正の整数のd*a(d)*a(n-k)すべての約数を計算し、これらすべてを合計し、で除算します。dknn-1

それはより速く実行できるようにするには、Pythonの3ラン(交換する///上記の関数で)とmemoize:

import functools
a = functools.lru_cache(None)(a)

これを行うと、a(50) = 425976989835141038353即座に計算されます。


かっこいい。私はそのlru_cache()機能をメモしていると思いますか?
パトリックロバーツ

@PatrickRobertsはい、通常は関数デコレーターとして使用されますが、関数に手動で適用することもできます。
-orlp

@PatrickRobertsのドキュメントをlru_cache次に示します。
PM 2Ring

この関数はTrueを返しますn<2。私はそれがために大丈夫だと思うn=1のPythonであるため、True数値コンテキストで1と評価されますが、a(0)あなたがしてこれを修正でき0を返す必要がありますn<2 and n or sum...が、よりコンパクトな方法があるかもしれません。
PM 2Ring

ゼロのバブルを配置する方法が1つあるという議論ができると思いますが、それはA000081と一致していません。OTOH、正の値のみを解く必要があるn場合は、このコーナーケースを無視しても安全ですn。これは、higherの再帰呼び出しに影響を与えないためです。
PM 2Ring

10

GNU Prolog、98バイト

b(x,0,x).
b(T/H,N,H):-N#=A+B+1,b(H,A,_),b(T,B,J),H@>=J.
c(X,Y):-findall(A,b(A,X,_),L),length(L,Y).

この回答は、Prologが最も単純なI / Oフォーマットでさえ苦労する方法の良い例です。問題を解決するアルゴリズムではなく、問題を説明することにより、真のPrologスタイルで動作します。それは、合法的なバブル配置としてカウントするものを指定し、Prologにそれらすべてのバブル配置を生成してからカウントします。生成には55文字(プログラムの最初の2行)が必要です。カウントとI / Oは、残りの43(3行目、および2つの部分を区切る改行)を取ります。これは、OPが言語がI / Oに苦しむ原因になると期待していた問題ではないと思います!(注:Stack Exchangeの構文強調表示により、これは読みにくくなり、簡単ではないため、オフにしました)。

説明

実際には機能しない同様のプログラムの擬似コードバージョンから始めましょう。

b(Bubbles,Count) if map(b,Bubbles,BubbleCounts)
                and sum(BubbleCounts,InteriorCount)
                and Count is InteriorCount + 1
                and is_sorted(Bubbles).
c(Count,NPossibilities) if listof(Bubbles,b(Bubbles,Count),List)
                       and length(List,NPossibilities).

どのようにb機能するかはかなり明確でなければなりません:ソート済みリスト(等しいマルチセットを比較するマルチセットの単純な実装)を介してバブルを表し、1つのバブル[]のカウントが1で、大きなバブルのカウントがあります内部のバブルの総数に1を足したものに等しい。カウント4の場合、このプログラムは(動作した場合)次のリストを生成します。

[[],[],[],[]]
[[],[],[[]]]
[[],[[],[]]]
[[],[[[]]]]
[[[]],[[]]]
[[[],[],[]]]
[[[],[[]]]]
[[[[],[]]]]
[[[[[]]]]]

このプログラムはいくつかの理由で答えとしては不適切ですが、最も緊急なのは、Prologには実際にはmap述語がないことです(そして、それを書くにはバイトがかかりすぎます)。そのため、代わりに次のようなプログラムを作成します。

b([], 0).
b([Head|Tail],Count) if b(Head,HeadCount)
                    and b(Tail,TailCount)
                    and Count is HeadCount + TailCount + 1
                    and is_sorted([Head|Tail]).
c(Count,NPossibilities) if listof(Bubbles,b(Bubbles,Count),List)
                       and length(List,NPossibilities).

ここでのもう1つの大きな問題は、Prologの評価順序が機能する方法のために、実行時に無限ループに入ることです。ただし、プログラムをわずかに再配置することで無限ループを解決できます。

b([], 0).
b([Head|Tail],Count) if Count #= HeadCount + TailCount + 1
                    and b(Head,HeadCount)
                    and b(Tail,TailCount)
                    and is_sorted([Head|Tail]).
c(Count,NPossibilities) if listof(Bubbles,b(Bubbles,Count),List)
                       and length(List,NPossibilities).

我々は、彼らが何であるかを知っている前に、私たちは一緒にカウントを追加している- -これはかなり奇妙に見えるかもしれませんが、GNU Prologの者は、#=非因果算術のその種を処理することが可能である、そしてそれは非常に最初の行だからb、とHeadCountTailCount必須の両方未満であることCount(既知)、再帰項が一致できる回数を自然に制限する方法として機能するため、プログラムは常に終了します。

次のステップは、これを少しゴルフすることです。以下のような略語使用して、単一文字の変数名を使用して、空白文字を削除する:-ためif,のためにand、使用するsetofのではなくlistof(それは短い名前を持っており、この場合には、同じ結果を生成)、および使用するsort0(X,X)のではなくis_sorted(X)ので(is_sorted実際には本当の関数ではありません、私はそれを作りました):

b([],0).
b([H|T],N):-N#=A+B+1,b(H,A),b(T,B),sort0([H|T],[H|T]).
c(X,Y):-setof(A,b(A,X),L),length(L,Y).

これはかなり短いですが、もっと良くすることは可能です。重要な洞察は、[H|T]リスト構文が進むにつれて本当に冗長になるということです。Lispプログラマーが知っているように、リストは基本的にコンスセルで構成されています。コンスセルは基本的に単なるタプルであり、このプログラムのどの部分もリスト組み込みをほとんど使用していません。Prologにはいくつかの非常に短いタプル構文があります(私のお気に入りはA-Bですが、2番目のお気に入りはA/Bです。この場合、読みやすいデバッグ出力を生成するため、ここで使用しています)。またnil、2文字に固執するのではなく、リストの最後に独自の1文字を選択することもできます[](私はを選択xしましたが、基本的には何でも機能します)。の代わりに[H|T]、を使用してT/H、から出力を取得できますb これは次のようになります(タプルのソート順はリストのソート順と少し異なるため、これらは上記と同じ順序ではありません)。

x/x/x/x/x
x/x/x/(x/x)
x/(x/x)/(x/x)
x/x/(x/x/x)
x/(x/x/x/x)
x/x/(x/(x/x))
x/(x/x/(x/x))
x/(x/(x/x/x))
x/(x/(x/(x/x)))

これは、上記のネストされたリストよりも読みにくいですが、可能です。精神的にxsをスキップ/()し、バブル(または/、コンテンツがない()後、ない場合は単純に縮退したバブル)として解釈し、要素は上記のリストバージョンと1対1(無秩序の場合)に対応します。

もちろん、このリスト表現は非常に短いにもかかわらず、大きな欠点があります。言語に組み込まれていないためsort0、リストがソートされているかどうかを確認することはできません。sort0とにかくかなり冗長であるため、手作業で行うことは大きな損失ではありません(実際、[H|T]リスト表現で手作業で行うことは、まったく同じバイト数になります)。ここで重要な洞察は、リストがその尾がソートされている場合ならば、ソートされている場合書かれた小切手などのプログラムが見ていることであるその尾がソートされ、そのために、冗長なチェックがたくさんあり、それを活用することができます。代わりに、最初の2つの要素が正しいことを確認するだけです(リスト自体とそのすべてのサフィックスがチェックされると、リストが最終的にソートされることを保証します)。

最初の要素には簡単にアクセスできます。それはリストの先頭ですH。ただし、2番目の要素はアクセスがかなり難しく、存在しない場合があります。幸いなことに、x(Prologの一般化された比較演算子を介して)検討しているすべてのタプルよりも少ない@>=ため、シングルトンリストの「2番目の要素」を考慮することができx、プログラムは正常に動作します。実際に2番目の要素にアクセスする場合、最も簡単な方法は、3番目の引数(out引数)をに追加するbことです。これはx、基本ケースとH再帰ケースで戻ります。これは、の2回目の再帰呼び出しからの出力としてテールのヘッドを取得できることを意味します。Bもちろん、テールのヘッドはリストの2番目の要素です。だからb今このようになります:

b(x,0,x).
b(T/H,N,H):-N#=A+B+1,b(H,A,_),b(T,B,J),H@>=J.

基本ケースは十分単純です(空のリスト、0のカウントを返す、空のリストの「最初の要素」はx)です。再帰的なケースは、以前と同じ方法で始まります(T/Hでなく表記法[H|T]を使用Hし、追加の引数として)。頭の再帰呼び出しの余分な引数は無視しJますが、末尾の再帰呼び出しに保存します。次に、リストがソートされていることを確認するために、Hそれ以上J(つまり、リストに少なくとも2つの要素がある場合、最初の要素が2番目の要素以上である)を確認するだけです。

残念ながら、setof以前の定義cをのこの新しい定義と一緒に使用しようとすると適合bしますGROUP BY。これは、SQLとほぼ同じ方法で未使用のoutパラメーターを処理するためです。必要な処理を実行するように再構成することは可能ですが、その再構成にはコストがかかります。代わりに、findallより便利なデフォルトの動作を持ち、2文字だけ長いを使用して、次の定義を提供しcます。

c(X,Y):-findall(A,b(A,X,_),L),length(L,Y).

そして、それが完全なプログラムです。バブルパターンを簡潔に生成し、それらをカウントするためにバイトの負荷全体を費やします(findallジェネレーターをリストに変換するためにかなり長い時間を必要とlengthします。


「Prologには実際にはマップ述語がありません」:Prologにはmaplist/2-8述語がありますが、これによってここで短くなるかどうかはわかりません。
1

@Fatalize:ええ、新しいバージョンで追加されたようです。それは私が持っているインストールのドキュメントにはなく、実際には機能しません:| ?- maplist(reverse,[A,B]). uncaught exception: error(existence_error(procedure,maplist/2),top_level/0)

それは本当に奇妙です。maplistは、主要なPrologディストリビューション(SWI-PrologやSiCStusなど)で提供される非常に一般的に使用される述語です
1

10

Mathematica、68バイト

これはゼロからの実装で(Mathematicaでも)破られる可能性がありますが、組み込みバージョンは次のとおりです。

<<NumericalDifferentialEquationAnalysis`
Last@ButcherTreeCount[#+1]&

ButcherTreeCountは0でインデックス付けされているため、[#+1]であり、引数までのすべての値のリストを返しますLast@。ただし、それ以外の場合は、この関数の組み込み関数です。ただし、パッケージをロードする必要があります。これが最初の行の動作です。


8
「もちろんMathematicaにはそのためのビルトインがあります。」
-orlp
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.