Die Rechnung aufteilen

12

Aufgabe

Angenommen, der pPole muss eine Rechnung teilen. Jeder von ihnen wird durch ein Triple identifiziert, (Name, n, k)das sich zusammensetzt aus:

  • Name: der Name ;
  • n: der Betrag, den sie / er zu zahlen hat ;
  • k: der Betrag, den sie / er tatsächlich gezahlt hat .

Hier gilt es herauszufinden, wer wem was schuldet.

Annahmen

  • Die Ein- und Ausgabe kann in jedem beliebigen Format erfolgen.

  • p N,n N+, k N.

  • p >1.

  • Namen sind eindeutige Zeichenfolgen beliebiger Länge, die aus Kleinbuchstaben bestehen.

Lösung

Die Lösung wird durch die Mindestanzahl von Transaktionen zwischen den pPersonen dargestellt. insbesondere sind sie dreifach(from, to, amount)

  • from: namevon der Person, die Geld gibt;
  • to: nameder Person, die Geld erhält;
  • amount: Geldbetrag der Transaktion.

HINWEIS : Die Summe aller Schulden ( n) kann von der Summe aller bereits bezahlten Beträge ( k) abweichen . In diesem Fall müssen Sie die Ausgabe ('owner', Name, amount)oder (Name, 'owner', amount)das ausgewählte Format hinzufügen . Jeder Name wird niemals sein. ownerDer String 'owner' ist flexibel.

Wenn mehrere Mindestmengen vorhanden sind, wählen Sie die mit der Mindestsumme aller Transaktionsbeträge (Absolutwerte) aus. Wählen Sie im Falle eines Unentschieden eines davon aus.

Testfälle:

inputs(Name,n,k):
[('a',30,40),('b',40,50),('c',30,15)]
[('a',30,30),('b',20,20)]
[('a',30,100),('b',30,2),('c',40,0)]
[('a',344,333),('b',344,200),('c',2,2)]
[('a',450,400),('b',300,300),('c',35,55)]

outputs(from, to, amount):
[('c','a',10),('c','b',5),('owner','b',5)] or [('c','b',10),('c','a',5),('owner','a',5)]
[]
[('owner','a',2),('b','a',28),('c','a',40)] PS: [('owner','a',2),('b','a',68),('c','b',40)] has the same number of transactions, but it is not a valid answer, because the total amount of its transaction is greater than that of the proposed solution.
[('a','owner',11),('b','owner',144)]
[('a','owner',30),('a','c',20)]

Das ist Code-Golf: Der kürzeste Code gewinnt .

Vedant Kandoi
quelle
1
Ich denke, Sie sollten ändern "Sie müssen das einfachste Szenario ausgeben, das die geringste Anzahl von Transaktionen erfordert." zu "Sie müssen das Szenario ausgeben, das die geringste Anzahl von Transaktionen erfordert. Wenn mehrere solcher Szenarios vorhanden sind, wählen Sie eines mit der geringsten Gesamtzahl von Transaktionen aus." da halte ich es für klarer.
Jonathan Allan
1
Schöne Herausforderung. Es werden jedoch wahrscheinlich komplexere Testfälle erforderlich sein, um sicherzustellen, dass die Lösungen immer optimal sind.
Arnauld
3
Was ist "kleinste fiktive Summe"?
Lirtosiast
1
@ JonathanAllan immer noch durch das Wort "fiktive" verwirrt. wo kommt das her Basierend auf Testfall 3 sieht es so aus, als sollte man Antworten vorziehen, bei denen nicht dieselbe Person sowohl gibt als auch empfängt? Ist das korrekt? auch warum wird das als fiktiv bezeichnet?
Jonah
1
@Jonah Ich habe "total fiktive" verwendet, da die Richtungen der Transaktionen nicht berücksichtigt werden sollten (nur ihre absolute Größe), obwohl ich jetzt merke, dass es etwas redundant ist (da zwei Transaktionen, die sich gegenseitig entgegenwirken, nicht als einmal unentschieden gelten würden !). [Begrifflich ist nur der Begriff, der im Finanzwesen verwendet wird.]
Jonathan Allan

Antworten:

2

JavaScript (ES6),  252 227 223 222  215 Bytes

Übernimmt die Eingabe als [[n0, k0, name0], [n1, k1, name1], ...].

Transaktionen in der Lösung können entweder positiv oder negativ sein. Der Eigentümer heißt undefiniert .

a=>(m=g=(B,t,s)=>B.some(x=>x)?B.map((b,x)=>B.map((c,y)=>b*c<0&b*b<=c*c&&g(C=[...B],[...t,[a[x][2],b,a[y][2]]],s+a.length-1/b/b,C[C[y]+=b,x]=0))):m<s||(r=t,m=s))([...a.map(([x,y])=>t-(t+=y-x),t=0),t],[],a.push(g))&&r

Probieren Sie es online!

Kommentiert

a => (                              // a[] = input array
  m =                               // initialize m to a non-numeric value
  g = (B, t, s) =>                  // g = function taking: B = balances, t = transactions,
                                    //     s = score of the current solution
    B.some(x => x) ?                // if at least one balance is not equal to 0:
      B.map((b, x) =>               //   for each balance b at position x:
        B.map((c, y) =>             //     for each balance c at position y:
          b * c < 0 &               //       if b and c are of opposite sign
          b * b <= c * c &&         //       and |b| <= |c|,
          g(                        //       do a recursive call to g:
            C = [...B],             //         - with a copy C of B
            [ ...t,                 //         - append the new transaction to t[]
              [a[x][2], b, a[y][2]] //           in [from_name, amount, to_name] format
            ],                      //
            s + a.length - 1/b/b,   //         - add (a.length - 1/b²) to s
            C[C[y] += b, x] = 0     //         - update C[y] and clear C[x]
          )                         //       end of recursive call
        )                           //     end of inner map()
      )                             //   end of outer map()
    :                               // else:
      m < s ||                      //   if the score of this solution is lower than m,
      (r = t, m = s)                //   update r to t and m to s
)(                                  // initial call to g:
  [                                 //   build the list of balances:
    ...a.map(([x, y]) =>            //     each balance is equal to:
      t - (t += y - x),             //     due_value - paid_value
      t = 0                         //     keep track of the total t ...
    ),                              //
    t                               //   ... which is appended at the end of this array
  ],                                //   (this is the balance of the owner)
  [],                               //   start with t = []
  a.push(g)                         //   append a dummy owner to a[]; start with s = 1
) && r                              // return r
Arnauld
quelle