Dollar-Teilbarkeit und perfekte Veränderung

11

Ich habe 15 Dollar in der Tasche. Ebenso bin ich in einem Geschäft, das kein Wechselgeld gibt. Beim Surfen sehe ich einen Artikel, der 10 US-Dollar kostet (inklusive Steuern). Kann ich diesen Artikel kaufen, ohne Geld zu verlieren?

In diesem Fall lautet die Antwort ja. Egal wie meine 15 $ aufgeteilt sind (eine 10 und eine 5 oder drei 5 oder etwas anderes), ich werde immer genau die 10 $ haben, die benötigt werden.

Als zweites Beispiel habe ich 0,16 Dollar in der Tasche. Welche anderen Geldbeträge muss ich genau bezahlen können?

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

Was ist, wenn ich 0,27 USD in der Tasche habe?

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

Im obigen Fall gab es nur wenige Geldbeträge, für die ich immer ein perfektes Wechselgeld hätte.

Deine Aufgabe

Schreiben Sie das kürzeste Programm (oder die benannte Funktion), das A) einen ganzzahligen Geldbetrag und B) eine Liste möglicher Stückelungen als Eingabe verwendet und eine Liste der Geldbeträge ausgibt, für die ich eine perfekte Änderung haben muss. Die Eingabe kann entweder STDIN oder Argumente für das Programm oder die Funktion sein. Ich werde bei der Eingabeformatierung nicht sehr streng sein. Es kann übereinstimmen, wie Ihre Sprache Arrays formatiert.

Vielleicht eine ausführlichere Erklärung

Ich habe einen bestimmten Geldbetrag in der Tasche, der sich aus einer Reihe möglicher Währungsdemonstrationen zusammensetzt. Wenn ich 8 Dollar habe und weiß, dass die möglichen Stückelungen 2 und 3 Dollar sind, dann gibt es nur so viele verschiedene Kombinationen von Scheinen, die in meiner Tasche sein könnten. Das sind 2+2+2+2und 3+3+2. Um einen genauen Geldbetrag produzieren zu können, muss ich in der Lage sein, diese Menge nur mit den Rechnungen zu produzieren, die sich in meiner Tasche befinden. Wenn ich vier 2er hätte, könnte ich produzieren 2, 4, 6, or 8. Wenn ich zwei 3er und eine 2er hätte, könnte ich produzieren. 2, 3, 5, 6, or 8Da ich nicht weiß, welche dieser Kombinationen ich tatsächlich in meiner Tasche habe, reduziert sich meine endgültige Antwort auf 2, 6, 8. Dies sind die Werte, von denen ich weiß, dass ich sie angesichts der Gesamtmenge und der möglichen Stückelungen aus meiner Tasche produzieren kann.

Handberechnete Beispiel-E / A.

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
PhiNotPi
quelle
Das ist sehr unklar.
Motoku
@FryAmTheEggman Ich habe eine "vielleicht eine detailliertere Erklärung" hinzugefügt. Lassen Sie mich wissen, wenn es noch verwirrend ist. (Ich habe auch einen
Randfall
Ich sehe nicht, wie es dir geht 6 [2, 3, 4]. Kannst du nicht 2+2+23 machen und 3+3nicht 2 und 4 machen?
xnor
@xnor du bist richtig, behoben.
PhiNotPi
Sollte das Programm für alle Eingaben in angemessener Zeit ausgeführt werden? ZB ist meine kürzeste Idee in der Startmenge exponentiell und 2 ^ 1500 ist eine Menge von allem.
Randomra

Antworten:

2

Python 2, 200 197 193 140 Bytes

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}

(Danke an @Nabb für Tipps)

Hier ist eine schlecht Golf Lösung für den Moment, um die Dinge in Gang zu bringen. Call with g(16, [1, 5, 10, 25])- output ist eine Menge mit den relevanten Nennwerten.

Der Ansatz ist unkompliziert und gliedert sich in zwei Schritte:

  • funtersucht alle Möglichkeiten, nmit Stückelungen D(z. B. [1, 5, 10]) zu erreichen, und berechnet für jede alle Beträge, die mit diesen Stückelungen (z set([0, 1, 5, 6, 10, 11, 15, 16]). B. ) erzielt werden können .
  • gberechnet die Schnittpunkte der Ergebnisse von fund entfernt dann 0 für die endgültige Antwort.

Das Programm löst die Fälle 1-5 und 7 fein, stapelt Überläufe auf 6 und dauert ewig auf 8.

Wenn es keine Lösung gibt (z. B. g(7, [2, 4, 6])), gibt das Programm einen leeren Satz zurück. Wenn in einem solchen Fall ein Fehler ausgegeben werden darf, ist hier ein kürzerer g:

g=lambda*a:reduce(set.__and__,f(*a))-{0}
Sp3000
quelle
g=lambda L,c=0:L and g(L[1:],c)|g(L,c+L.pop(0))or{c}ist etwas kürzer
Nabb
Ein bisschen mehr, indem Sie -{0}in g [L]*-~n[L][-n:]
wechseln
1

JavaScript (ES6) 162 203 207

Bearbeiten Die Art und Weise, wie Ergebnismengen in Array r geschnitten werden, wurde geändert. Ein bisschen schneller, aber der Algorithmus stinkt immer noch.

Eine ausführlichere Erklärung folgt.
Kurz gesagt: c ist eine rekursive Funktion, die alle möglichen Unterteilungen auflistet. k ist eine rekursive Funktion, die alle möglichen Summen ohne Wiederholungen auflistet. Jede neue Ergebnismenge, die mit der Funktion k gefunden wurde, wird mit der zuvor gefundenen Menge verglichen. Es werden nur die gemeinsamen Ergebnisse beibehalten.

Warum ist es so langsam? Es ist keine gute Idee, eine Zielsumme von beispielsweise 1500 und ein einzelnes Stück Wert 1 zu verwalten und alle möglichen Summen aufzulisten.

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

Ungolfed

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
}

Test In Firefox / Firebug - Konsole

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

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

(Zeit 84 ms)

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

[1, 2, 25, 26, 27]

(Zeit 147252 ms, also nicht sooo schnell)

edc65
quelle
0

Wolfram Methematica, 104 Bytes

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

Ungolfed (vom Ende lesen):

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
                ]&
Savenkov Alexey
quelle