金の鎖を切る


32

旅行者は町の外のホテルにn日間滞在する必要があります。彼は現金が不足しており、クレジットカードの有効期限が切れています。しかし、彼はnの金の鎖を持っていますリンクます。

このホテルのルールでは、住民は毎朝家賃を支払う必要があります。旅行者は、マネージャーとの間でゴールデンチェーンのリンクを毎日支払うことに同意します。しかし、マネージャーはまた、旅行者が毎日支払いながらチェーンに可能な限り損害を与えないように要求しています。言い換えれば、彼はできるだけ少ないリンクをカットする解決策を考え出さなければなりません。

リンクを切断すると、3つのサブチェーンが作成されます。1つは切断されたリンクのみを含み、もう1つは両側にあります。たとえば、長さ8のチェーンの3番目のリンクを切断すると、長さ[2、1、5]のサブチェーンが作成されます。マネージャーは変更を喜んで行うため、旅行者は長さ1のチェーンで1日目を支払い、次に長さ2のチェーンで2日目を支払い、最初のチェーンを取り戻すことができます。

コードは長さnを入力する必要があります最小長のカットへのリンクのリストを出力する必要があります。

ルール

  • nは0より大きい整数です。
  • リンクには0ベースまたは1ベースのインデックスを使用できます。
  • 一部の数値では、ソリューションは一意ではありません。たとえば、n = 15両方[3, 8][4, 8]有効な出力です。
  • リストを返すか、適切な区切り記号を付けて印刷できます。
  • これはであるため、バイト単位の最短コードが優先されます。

テストケース

Input          Output (1-indexed)
1              []
3              [1]
7              [3]
15             [3, 8]
149            [6, 17, 38, 79]

詳細な例

以下のためのN = 15、リンク3及び長さのサブチェーンで8つの結果を切断します[2, 1, 4, 1, 7]。これは有効なソリューションです:

 1 = 1
 2 = 2
 3 = 1+2
 4 = 4
 5 = 1+4
 6 = 2+4
 7 = 7
 8 = 1+7
 9 = 2+7
10 = 1+2+7
11 = 4+7
12 = 1+4+7
13 = 2+4+7
14 = 1+2+4+7
15 = 1+1+2+4+7

カットが1つしかないソリューションは存在しないため、これが最適なソリューションです。

補遺

この問題は整数分割に関連していることに注意してください。1からnまでのすべての整数がPのサブセットである少なくとも1つのパーティションを持つようなnのパーティションPを探しています。

ここだYouTubeの動画この問題の一つの可能なアルゴリズムについては。


私はあなたの「変化を起こす」参照を理解していません。投稿された例では、2日目に2リンクチェーンで支払います(また、1リンクチェーン(前日で支払った)を変更として、説明どおりに戻します)。ただし、3日目にはで支払います1+2。2番目の2リンクチェーンはどこから来たのですか?
Flater

4
@Flaterマネージャーはすでに持っています。追加料金を支払うだけです。実際には、RHSは、管理者が毎日を所有していることをリンクされている
polfosolఠ_ఠ

回答:


15

05AB1E23 11 8バイト

ΔÍN-;иg=

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

0ベースのインデックスを使用します。

説明:

             # start from the implicit input
Δ            # loop forever
 Í           # subtract 2
  N-         # subtract the current iteration number
    ;        # divide by 2
     и       # create a list of length x
      g      # get the length of the list
       =     # print

иg noopのように見えますが、実際には2つの有用なことを行います。整数に切り捨てます(; floatを返します)、xが負の場合にインタープリターをクラッシュさせます(これが唯一の終了条件です)。


23バイトのソリューションは非常に異なるアプローチを使用したので、ここでは後世のためです:ÅœʒR2äθP}ʒæOê¥P}θ2äθη€OTIO説明)。


2
回答を削除しました。私が42歳で、あなたが11歳であることは、私にとって恥ずかしさを感じないほどの違いです。;)でもいい答え、そしてで笑Ø.Ø。すべてのネガをフロアし、マッピングするために、ランダムなことを試しました-1か?とにかく、非常に良い答えであり、私が予想したよりもずっと短い。悪い42バイトを投稿した後、約20バイトを考えていました。
ケビンクルイッセン

2
@KevinCruijssen Nnopeは、Ø.Ø実際に私の最初のアイデアでした。コメントはランダムなものをしようとする私を触発:私が見つけた®Ÿàï®Mともっと重要なのは、иgこの素敵な8-byterを得ています。osabieは多くの場合(0による除算、間違ったタイプなど)クラッシュよりも何もしないことを好むので、このクラッシュは便利です。
グリムミー

2
Hehe、05AB1Eはクラッシュすることはないはずですが、クラッシュすることは少し面倒なこともあります。レガシーでは、クラッシュする方法すら知りませんでした。手動で呼び出すことができるゼロエラー。xD新しいバージョンでは、特定の組み込み関数に誤った引数を与えると、かなり頻繁にエラーでクラッシュします。そして再び素敵な-3。
ケビンクルーッセン

2
「xが負の場合、インタープリターをクラッシュさせます(これが唯一の終了条件です)。」-私はそれが大好きです
ジョン・ドヴォラック

9

Python 2、75バイト

f=lambda n,i=0:n>=i<<i and f(n,i+1)or[min(n,2**j*i-i+j)for j in range(1,i)]

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


説明:

基本数がカット数と一致する「バイナリ」チャンクのシーケンスを構築します。

例えば:

63 3つのカットで行うことができます。これは、ベース4のパーティションを意味します(3つの単一リングがあるため)。

Cuts:5, 14, 314 1 8 1 16 1 32(sorted:)のチェーンを提供します1 1 1 4 8 16 32

すべての番号を作成できます。

1       1
2       1 1
3       1 1 1
4       4
...
42      1 1 8 32
...
62      1 1 4 8 16 32
63      1 1 1 4 8 16 32

他の例:

18: 4,11        ->  3 1 6 1 7
27: 5,14,27     ->  4 1 8 1 13 1
36: 5,14,31     ->  4 1 8 1 16 1 5
86: 6,17,38,79  ->  5 1 10 1 20 1 40 1 7

1
f=スタートに追加すべきではありませんか?fラムダ関数での呼び出しを使用しているため、定義しているのと同じラムダを参照しているとしか想定できません。
randomdude999

@ randomdude999、ええ、私は忘れていた...
TFeld

@ randomdude999は、そのルールがすべての言語に適用されるのですか、それともPythonのみですか?原因このチャレンジでは、純粋なラムダであるjavascriptの回答が表示されます...
Shadow

3
@Shadowすべての言語に適用されますが、再帰ラムダのみに適用されます。
TFeld

1
@Shadowより一般的なルールは、チャレンジで明示的に許可されていない限り、コードで定義されていないか、言語でグローバルに定義されていないものを参照できないことです。最も一般的なケースは再帰関数ですが、これは他の状況にも当てはまります。この答えは別の例です。f再帰的ではありませんが、コードで参照されているため、名前を付ける必要があります。
アーナウルド

8

R77 69バイト

アーロン・ヘイマンのおかげで-8バイト

pmin(n<-scan(),0:(k=sum((a=2:n)*2^a<=n))+cumsum((k+2)*2^(0:k))+1)[-n]

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

kkk+12kn111kk+12k+14k+18k+1k+12k1。これが十分かつ最適であることを確認するのは簡単です。

(チェーンの全長を超える場合、最後のサブチェーンを短くする必要があるかもしれません。)

Ungolfed(以前の類似バージョンに基づく):

n = scan()                            # read input
if(n - 1){                            # If n==1, return NULL
  k = match(F, (a = 2:n) * 2 ^ a > n) # compute k
  b = (k + 1) * 2 ^ (1:k - 1)         # lengths of subchains
  c = 1:k + cumsum(b)                 # positions of cuts
  pmin(c, n )                         # if last value is >n, coerce it to n
}

(その値が k 私が述べているとおりです:我々が持っていると仮定します kカット。それからk ユニットのサブチェーンなので、最初のサブチェーンの長さが必要です k+1。最大ですべての長さを処理できるようになりました2k+1、次の長さが必要です 2k+2、その後 4k+4...したがって、最大の k カットは、これらのすべての長さを合計することにより得られます。 k+12k1

もし ak は最小の整数です n 必要な k カット、その後 akあるOEIS A134401は


特別な場合に役立つとは思わないn=1が、カットオフを生成する代替方法は再発である1, 4, 4a(n-1)-4a(n-2)
ピーターテイラー

@PeterTaylorコンピューティングでも同様の再発がありましたk。これはOEIS A134401に対応します。oeis.org/ A134401しかし、再帰関係の私の実装は、現在のコードよりも多くのバイトを使用します。
ロビンライダー


@AaronHaymanありがとう!のsum代わりに使用するスマートムーブmatch
ロビンライダー

69バイト、あなたを動揺させていたif文を取り除きました:オンラインで試してみてください!
アーロンヘイマン



2

C ++、109、107バイト

-ケビンのおかげで2バイト

#include<iostream>
main(){int n,k=0;for(std::cin>>n;++k<<k<n;);for(n-=k;n>0;k*=2,n-=k+1)std::cout<<n<<',';}

アルゴリズムは、Robin Ryderの答えに似ています。コードはコンパイル可能な完全な形式で記述されています。それを試してみてください!

詳細:

std::cin>>n;               // get the value of n as input
while(++k<<k<n);           // determine k
for(n-=k;n>0;k*=2,n-=k+1)  // we don't need n, so the lengths...
    std::cout<<n<<' ';     // of links are subtracted repeatedly

これには、同じバイト長のCバリエーションがあります(個別の回答は必要ないようです)。

#include<stdio.h>
main(){int n,k=0;for(scanf("%d",&n);++k<<k<n;);for(n-=k;n>0;k*=2,n-=k+1)printf("%d,",n);}

ゴルフの2つの小さなこと:=0after k0デフォルトで削除されます。std::cin>>n;while(++k<<k<n);することができますfor(std::cin>>n;++k<<k<n;);。私はまた、for(n-=k;n>0;k*=2,n-=k+1)何かを組み合わせることによって何らかの形で単純化できるという感覚を持っていますが、どうすればいいのかわかりません。PS:コンマ区切り文字をスペースに変更すると、末尾の1つの
imo

1
@KevinCruijssenありがとう。ただし、一部のコンパイラは、非静的変数にデフォルト値を割り当てません。だから=0、携帯性のために必要だと思った;)また、後のスペース#includeは必要ないことにも気づいた。
ポルフォソルఠ_ఠ

わかった 私はC ++の知識があまりないので、回答でリンクしたオンラインコンパイラを使用して、いくつかのことをテストしました。:)あなたは私のコメントで提案した2番目の変更を忘れました:forループへのwhileループとそのstd::cin>>n中への配置。
ケビンクルイッセン


1

Retina 0.8.2、61バイト

.+
11,$&$*
+`\b(1+),(\1(1*)1?\3)$
1$2¶1$1,$3
1+,
1
1A`
1+
$.&

オンラインでお試しください!@Grimyの回答の1インデックス付きポート。説明:

.+
11,$&$*

で開始しN=2、入力を単項に変換します。

+`\b(1+),(\1(1*)1?\3)$

N入力から減算を繰り返してから2で除算しようとします。

1$2¶1$1,$3

成功した場合は、前の行の入力より1つ多く記憶Nし、現在の行で増分し、入力を新しい値に更新します。

1+,
1

N最後の値を削除して増分し、1インデックスも付けられるようにします。

1A`

インクリメントされた元の入力を削除します。

1+
$.&

結果を10進数に変換します。


弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.