法案を分割する


12

仕事

pが法案を分割しなければならないと仮定します。それらのそれぞれは、以下(Name, n, k)で構成されるトリプルによって識別されます。

  • Name名前 ;
  • n彼女/彼が支払わなければならない量
  • k彼女/彼が実際に支払った金額

ここでの課題は、誰が誰に負っているのかを知ることです。

仮定

  • 入力と出力は、任意の便利な形式にすることができます。

  • p Nn N+ k N

  • p >1。

  • 名前は、小文字のアルファベット文字で構成される任意の長さの一意の文字列です。

解決

ソリューションは、p人々の間の最小のトランザクションセットで表されます。特にトリプルです(from, to, amount)

  • fromnameお金を与える人の
  • tonameお金を受け取る人の
  • amount:トランザクションの金額。

:すべての負債の合計(n)は、すでに支払われたすべての金額の合計()と異なる場合がありますk。この場合、出力('owner', Name, amount)または選択(Name, 'owner', amount)した形式で追加する必要があります。名前は、すべてになることはありませんowner【選択文字列「所有者は」柔軟です。

複数の最小セットが存在する場合は、すべてのトランザクション量(絶対値)の合計が最小のものを選択します。同点の場合は、いずれかを選択します。

テストケース:

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

これはcode-golfです。最短のコードが勝ちます。


1
「必要なトランザクション数が最も少ない最も単純なシナリオを出力する必要があります」を変更する必要があると思います。「最小数のトランザクションを必要とするシナリオを出力する必要があります。そのようなシナリオが複数存在する場合は、トランザクションの合計合計が最小のシナリオを選択してください。」私はそれがより明確だと信じているので。
ジョナサンアラン

1
ナイスチャレンジ。ただし、ソリューションが常に最適であることを確認するには、より複雑なテストケースが必要になるでしょう。
アーナウルド

3
「最小合計概念」とは何ですか?
リトシアスト

1
@JonathanAllanは、「概念」という言葉にまだ混乱しています。それはどこから来たのですか?テストケース3に基づいて、同じ人が与えたり受け取ったりしない答えを好むように見えますか?あれは正しいですか?また、なぜそれが概念的と説明されているのですか?
ジョナ

1
@Jonah「合計概念」を使用したのは、トランザクションの方向を考慮する必要がないためです(絶対サイズのみ)。 !)。[概念は金融で使用される用語です。]
ジョナサンアラン

回答:


2

JavaScript(ES6)、 252 227 223 222  215バイト

入力をとして受け取ります[[n0, k0, name0], [n1, k1, name1], ...]

ソリューション内のトランザクションは、ポジティブまたはネガティブのいずれかです。所有者はundefinedと呼ばれます。

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

オンラインでお試しください!

コメント済み

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
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.