Tách hóa đơn


12

Bài tập

Giả sử rằng ppepole phải chia một hóa đơn; mỗi người trong số họ được xác định bởi một bộ ba (Name, n, k)gồm:

  • Name: tên ;
  • n: số tiền cô ấy / anh ấy phải trả ;
  • k: số tiền cô ấy / anh ấy thực sự đã trả .

Thách thức ở đây là tìm ra ai nợ ai.

Giả định

  • Đầu vào và đầu ra có thể ở bất kỳ định dạng thuận tiện.

  • p N,n N+, k N.

  • p >1.

  • Tên là các chuỗi duy nhất có độ dài tùy ý, bao gồm các ký tự chữ cái viết thường.

Giải pháp

Giải pháp được thể hiện bằng tập hợp giao dịch tối thiểu trong pnhân dân; đặc biệt họ là ba(from, to, amount)

  • from: namecủa người đưa tiền;
  • to: namecủa người nhận tiền;
  • amount: số tiền của giao dịch.

LƯU Ý : Tổng của tất cả các khoản nợ ( n) có thể khác với tổng của tất cả các khoản đã trả ( k). Trong trường hợp này, bạn phải thêm vào đầu ra ('owner', Name, amount)hoặc (Name, 'owner', amount)ở định dạng bạn đã chọn. Bất kỳ tên nào cũng sẽ không bao giờ owner. Chuỗi 'chủ sở hữu' là linh hoạt.

Nếu tồn tại một số bộ tối thiểu, hãy chọn bộ có tổng tối thiểu của tất cả số tiền giao dịch (giá trị tuyệt đối); trong trường hợp cà vạt, chọn một trong số họ.

Các trường hợp thử nghiệm:

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

Đây là code-golf: chiến thắng mã ngắn nhất .


1
Tôi nghĩ bạn nên thay đổi "Bạn phải đưa ra kịch bản đơn giản nhất đòi hỏi số lượng giao dịch ít nhất." thành "Bạn phải xuất kịch bản yêu cầu số lượng giao dịch ít nhất. Nếu tồn tại nhiều kịch bản như vậy, hãy chọn một kịch bản có tổng số giao dịch ít nhất." vì tôi tin rằng nó rõ ràng hơn.
Jonathan Allan

1
Thử thách đẹp. Nhưng nó có thể sẽ yêu cầu các trường hợp thử nghiệm phức tạp hơn để đảm bảo rằng các giải pháp thực sự luôn tối ưu.
Arnauld

3
"Tổng số ít nhất" là gì?
lirtosiast

1
@Jonathan ALLan vẫn bị lẫn lộn bởi từ ngữ not notio. nó đến từ đâu dựa trên trường hợp kiểm tra 3 có vẻ như người ta nên thích câu trả lời trong đó cùng một người không cho và nhận? đúng không? còn tại sao điều đó được mô tả là đáng chú ý?
Giô-na

1
@Jonah Tôi đã sử dụng "tổng số ghi chú" vì không nên xem xét các hướng của giao dịch (chỉ là kích thước tuyệt đối của chúng), mặc dù bây giờ tôi nhận ra rằng nó có phần dư thừa (vì có hai giao dịch chống lại nhau sẽ không được xem là phá vỡ giao dịch !). [Notional chỉ là thuật ngữ được sử dụng trong tài chính.]
Jonathan Allan

Câu trả lời:


2

JavaScript (ES6),  252 227 223 222  215 byte

Đưa đầu vào là [[n0, k0, name0], [n1, k1, name1], ...].

Giao dịch trong giải pháp có thể là tích cực hoặc tiêu cực. Chủ sở hữu được gọi là không xác định .

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

Hãy thử trực tuyến!

Đã bình luận

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
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.