Memecah Tagihan

12

Tugas

Misalkan ppepole harus membagi tagihan; masing-masing diidentifikasi oleh tiga yang (Name, n, k)terdiri dari:

  • Name: nama ;
  • n: jumlah yang harus dia bayar ;
  • k: jumlah yang sebenarnya dia bayar .

Tantangannya di sini adalah untuk mengetahui berapa banyak yang berutang siapa.

Asumsi

  • Input dan output dapat dalam format apa pun yang nyaman.

  • p N,n N+, k N.

  • p >1.

  • Nama adalah string unik dengan panjang arbitrer, terdiri dari karakter alfabet huruf kecil.

Larutan

Solusinya diwakili oleh set transaksi minimum di antara porang - orang; khususnya mereka tiga kali lipat(from, to, amount)

  • from: namedari orang yang memberi uang;
  • to: namedari orang yang menerima uang;
  • amount: jumlah uang transaksi.

CATATAN : Jumlah semua hutang ( n) dapat berbeda dari jumlah semua jumlah yang sudah dibayarkan ( k). Dalam hal ini, Anda harus menambahkan dalam output ('owner', Name, amount)atau (Name, 'owner', amount)dalam format yang Anda pilih. Nama apa pun tidak akan pernah owner. String 'pemilik' fleksibel.

Jika ada beberapa set mimimum, pilih satu dengan jumlah minimum semua jumlah transaksi (nilai absolut); dalam kasus dasi, pilih salah satunya.

Kasus uji:

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)]

Ini adalah kode-golf: kode terpendek menang .

Vedant Kandoi
sumber
1
Saya pikir Anda harus mengubah "Anda harus menampilkan skenario paling sederhana yang membutuhkan paling sedikit transaksi." untuk "Anda harus menampilkan skenario yang membutuhkan paling sedikit jumlah transaksi. Jika ada beberapa skenario seperti itu pilih satu dengan jumlah total transaksi terendah." karena saya percaya itu lebih jelas.
Jonathan Allan
1
Tantangan yang bagus. Tetapi mungkin perlu uji kasus yang lebih kompleks untuk memastikan bahwa solusi benar-benar selalu optimal.
Arnauld
3
Apa itu "notasi total total"?
lirtosiast
1
@Jonathan Allan masih bingung dengan kata "notional". dari mana datangnya berdasarkan uji kasus 3 sepertinya orang harus memilih jawaban di mana orang yang sama tidak memberi dan menerima? Apakah itu benar? juga mengapa itu digambarkan sebagai nosional?
Jonah
1
@Jonah saya menggunakan "total nosional" karena arah transaksi tidak boleh dianggap (hanya ukuran absolutnya), meskipun saya sekarang menyadari itu agak berlebihan (karena memiliki dua transaksi yang saling menangkal satu sama lain tidak akan dianggap sebagai penggabungan tanpa ikatan) !). [Notional hanya istilah yang digunakan dalam keuangan.]
Jonathan Allan

Jawaban:

2

JavaScript (ES6),  252 227 223 222  215 byte

Mengambil input sebagai [[n0, k0, name0], [n1, k1, name1], ...].

Transaksi dalam solusi dapat berupa positif atau negatif. Pemilik disebut tidak terdefinisi .

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

Cobalah online!

Berkomentar

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
sumber