ドルの分割可能性と完全な変化


11

ポケットに15ドルあります。同様に、私は変化をもたらさない店にいます。ブラウジング中に、価格が10ドル(税込)のアイテムを見つけました。お金を失うことなく、そのアイテムを購入できますか?

この場合、答えはイエスです。$ 15がどのように分割されても(1つ10と1つ5、3つ5つ、または他の何か)に関係なく、私は常に正確な10ドルを必要とします。

2番目の例として、ポケットに0.16ドルあります。正確に支払うことができる他の金額は何ですか?

Possible Divisions:
0.01, 0.05, 0.10
0.01, 0.05 x 3
0.01 x 16
Guaranteed Exact Change:
0.01, 0.05, 0.06, 0.10, 0.11, 0.15, 0.16

ポケットに$ 0.27ある場合はどうなりますか?

Possible Divisions:
0.01 x 2, 0.25
0.01 x 2, 0.05, 0.10 x 2
0.01 x 2, 0.05 x 3, 0.10
0.01 x 2, 0.05 x 5
0.01 x 27
Guaranteed Exact Change:
0.01, 0.02, 0.25, 0.26, 0.27

上記のケースでは、私が常に完全な変更を行うことができる金額はわずかでした。

あなたのタスク

A)整数の金額とB)入力として可能な金額のリストを受け取り、完全な変更が必要な金額のリストを出力する最短のプログラム(または名前付き関数)を記述します。入力は、STDINまたはプログラムまたは関数の引数のいずれかです。私は、入力の書式設定を非常に厳しくするつもりはありません。それはあなたの言語が配列をフォーマットする方法と一致します。

おそらくより詳細な説明

私はポケットに一定の金額を持っています。これは通貨の可能なデモのセットから形成されます。私が8ドルを持っていて、可能な額面が2ドルと3ドルであることを知っているなら、私のポケットに入れることができる法案の非常に多くの異なる組み合わせがあります。これらは2+2+2+2と3+3+2です。正確な金額を作成できるようにするには、ポケットにある請求書だけを使用してその数量を作成できる必要があります。4つの2があれば、を生成でき2, 4, 6, or 8ます。2つの3と2があった場合2, 3, 5, 6, or 8、これらの組み合わせのどれが実際にポケットに入っているかわからないため、最終的な答えはになり2, 6, 8ます。これらは私が値です知っている合計金額と可能な宗派与えられた、私は私のポケットから作り出すことができます。

手動計算のサンプルI / O

7 [3, 4]
3, 4, 7        //only one possible division into 3 + 4

7 [3, 2]
2, 3, 4, 5, 7  //the only division is 3 + 2 + 2

6 [2, 3, 4]
6     //divisions are 2+2+2, 3+3, 2+4 

16 [1, 5, 10, 25]          //this represents one of the examples above
1, 5, 6, 10, 11, 15, 16

27 [1, 5, 10, 25]          //another example from above
1, 2, 25, 26, 27

1500 [1, 5, 10, 25, 100, 500, 1000, 2000]
500, 1000, 1500

600 [100, 500, 1000, 2000]
100, 500, 600

600 [200, 1, 5, 10, 25, 100, 500, 1000, 2000]
600

これは非常に不明確です。
— motoku

@FryAmTheEggman「おそらくより詳細な説明」を追加しました。まだわかりにくい場合はお知らせください。(エッジケースもかなり無意味だったので削除しました。)
— PhiNotPi

どのようになっているのか分からない6 [2, 3, 4]。することはできません2+2+23をしない、と3+32と4を作ってみませんか?
— xnor

@xnorあなたは正しい、修正されました。
— PhiNotPi

プログラムはすべての入力に対して妥当な時間で実行する必要がありますか?例えば、私の最短のアイデアは開始量の指数関数的であり、2 ^ 1500は多くのものです。
— -randomra

回答:


2

パイソン2、200の 197 193 140バイト

f=lambda n,D,S={0}:sum([f(n-x,D,S|{x+y for y in S})for x in D],[])if n>0else[S]*-~n
g=lambda*a:(f(*a)and reduce(set.__and__,f(*a))or{0})-{0}

(ヒントについては@Nabbに感謝します)

物事を始めるための、今のところ不十分なゴルフのソリューションです。Call with g(16, [1, 5, 10, 25])—出力は、関連する金種のセットです。

アプローチは簡単で、2つのステップに分けられます。

  • fn宗派で到達するすべての方法D(例[1, 5, 10])を調べ、それぞれについて、これらの宗派で作成できるすべての金額(例set([0, 1, 5, 6, 10, 11, 15, 16]))を計算します。
  • gの結果の共通部分を計算してfから、最終回答の0を削除します。

プログラムは、ケース1〜5および7を問題なく解決し、6でスタックオーバーフローし、8で永遠にかかります。

解決策がない場合(例g(7, [2, 4, 6]):)、プログラムは空のセットを返します。そのような場合にエラーがスローされることが許可されている場合、ここに短いg:

g=lambda*a:reduce(set.__and__,f(*a))-{0}

g=lambda L,c=0:L and g(L[1:],c)|g(L,c+L.pop(0))or{c}少し短いです
— ナブ

-{0}gに移動し、[L]*-~n代わりに使用することでもう少し[L][-n:]
— -Nabb

1

JavaScriptの(ES6)162 203 207

編集配列rの結果セットを交差させる方法を変更しました。少し高速ですが、アルゴリズムは依然として悪臭を放ちます。

さらに詳細な説明が続きます。
まもなく:cはすべての可能な細区分を列挙する再帰関数です。kは、反復せずにすべての可能な合計を列挙する再帰関数です。k関数で見つかった新しい結果セットは、見つかった以前のセットと比較され、共通の結果のみが保持されます。

なぜそんなに遅いのですか?たとえば、1500のターゲット合計と1つの値1を管理する必要がある場合、すべての可能な合計を列挙することは得策ではありません。

F=(s,d,r,
  c=(s,i,t=[],v,k=(i,s,v)=>{for(;v=t[i++];)k(i,s+v);o[s]=s})=>
  {for(s||(i=k(o=[],0),r=(r||o).filter(v=>o[v]));v=d[i];++i)s<v||c(s-v,i,[...t,v])}
)=>c(s,0)||r

非ゴルフ

F=(s,d)=>{
  var r
  var c=(s,i,t=[])=>
  {
    var o=[],v
    var k=(i,s)=> // find all sums for the current list t, set a flag in the o array
    {
      var v
      for(;v=t[i++];)k(i,s+v)
      o[s]=s
    }

    if (s==0) {
      k(0,0)
      if (r)
        r = r.filter(v=>o[v]) // after first loop, intersect with current
      else
        r = o.filter(v=>v) // first loop, keep all results
    } 
    else
      for(;v=d[i];++i)
      { 
        if (s >= v) 
          c(s-v, i, t.concat(v))
      }
  }
  c(s,0) // enumerate all possible set of pieces
  return r
}

Firefox / FireBugコンソールでテストする

F(16,[1,5,10,25])

[1、5、6、10、11、15、16]

(時間84ミリ秒)

F(27, [1, 5, 10, 25]) 

[1、2、25、26、27]

(時間は147252ミリ秒なので、すっごく速くなりません)


0

Wolfram Methematica、104バイト

Rest@*Intersection@@Map[Total]/@Subsets/@Union[Sort/@IntegerPartitions[#,#,PadLeft[{},Length[#2]#,#2]]]&

Ungolfed(最後から読みます):

Rest@* // Removing 0
  Intersection@@   // Intersecting all totals
     Map[Total]/@  // Counting total of each subset
        Subsets/@  // Getting all the subsets of each partition
           Union[  // Removing duplicates 
              Sort/@ // Sorting each partition (to remove duplicates next)
                 IntegerPartitions[#,#,PadLeft[{},Length[#2]#,#2]] // Getting all Integer partitions
                ]&
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.