What algorithm to use to determine minimum number of actions required to get the system to “Zero” state?

前端 未结 10 515
隐瞒了意图╮
隐瞒了意图╮ 2020-11-30 18:25

This is kind of more generic question, isn\'t language-specific. More about idea and algorithm to use.

The system is as follows:

It registers small loans bet

相关标签:
10条回答
  • 2020-11-30 19:16

    Only if someone owes more than 2 people, whom also owe to the same set, can you reduce the number of transactions from the simple set.

    That is, the simple set is just find each balance and repay it. That's no more than N! transactions.

    If A owes B and C, and some subset of B C owe each other, so B owes C, then instead of: A -> B, A -> C (3 transactions). You'd use: A -> B, B -> C (2 transactions).

    So in other words you are building a directed graph and you want to trim vertices on order to maximize path length and minimize total edges.

    Sorry, I don't have an algorithm for you.

    0 讨论(0)
  • 2020-11-30 19:17

    I found a practical solution which I implemented in Excel:

    • find out who ows the most

    • let that person pay the complete amount he ows to the one who should get the most

    • that makes the first person zero

    • repeat this proces taken into account that one of (n-1) persons has a changed amount

    It should result in a maximum of (n-1) transfers and the nice thing about it is that no one is doing more than one payment. Take the (modified) example of jrandomhacker:

    a=-5 b=25 c=-20 d=3 e=-2 f=-1 (sum should be zero!)

    1. c -> b 20. result: a=-5 b=5 c=0 d=3 e=-2 f=-1

    2. a -> b 5 result: a=0 b=0 c=0 d=3 e=-2 f=-1

    3. e -> d 2 result a=0 b=0 c=0 d=1 e=0 f=-1

    4. f -> d 1

    Now, everyone is satisfied and no one is bothered by making two or more payments. As you can see, it is possible that one person recieves more than one payment (person d in this example).

    0 讨论(0)
  • 2020-11-30 19:20

    This actually looks like a job that the double entry accounting concept could help with.

    Your transactions could be structured as bookkeeping entries thus:

                              Alice  Bill  Charles  Balance
    Alice   -> Bill    $10      10    10-       0        0
    Bill    -> Alice    $1       9     9-       0        0
    Bill    -> Charles  $5       9     4-       5-       0
    Charles -> Alice    $5       4     4-       0        0
    

    And there you have it. At each transaction, you credit one ledger account and debit another so that the balance is always zero. At at the end, you simply work out the minimal number transactions to be applied to each account to return it to zero.

    For this simple case, it's a simple $4 transfer from Bill to Alice. What you need to do is to reduce at least one account (but preferably two) to zero for every transaction added. Let's say you had the more complicated:

                              Alice  Bill  Charles  Balance
    Alice   -> Bill    $10      10    10-       0        0
    Bill    -> Alice    $1       9     9-       0        0
    Bill    -> Charles  $5       9     4-       5-       0
    Charles -> Alice    $5       4     4-       0        0
    Charles -> Bill     $1       4     5-       1        0
    

    Then the transactions needed would be:

    Bill     -> Alice   $4       0     1-       1        0
    Bill     -> Charles $1       0     0        0        0
    

    Unfortunately, there are some states where this simple greedy strategy does not generate the best solution (kudos to j_random_hacker for pointing this out). One example is:

                     Alan  Bill  Chas  Doug  Edie  Fred  Bal
    Bill->Alan   $5    5-    5     0     0     0     0    0
    Bill->Chas  $20    5-   25    20-    0     0     0    0
    Doug->Edie   $2    5-   25    20-    2     2-    0    0
    Doug->Fred   $1    5-   25    20-    3     2-    1-   0
    

    Clearly, this could be reversed in four moves (since four moves is all it took to get there) but, if you choose your first move unwisely (Edie->Bill $2), five is the minimum you'll get away with.

    You can solve this particular problem with the following rules:

    • (1) if you can wipe out two balances, do it.
    • (2) otherwise if you can wipe out one balance and set yourself up to wipe out two in the next move, do it.
    • (3) otherwise, wipe out any one balance.

    That would result in the following sequence:

    • (a) [1] not applicable, [2] can be achieved with Alan->Bill $5.
    • (b) [1] can be done with Chas->Bill $20.
    • (c) and (d), similar reasoning with Doug, Edie and Fred, for four total moves.

    However, that works simply because of the small number of possibilities. As the number of people rises and the group inter-relations becomes more complex, you'll most likely need an exhaustive search to find the minimum number of moves required (basically the rules 1, 2 and 3 above but expanded to handle more depth).

    I think that is what will be required to give you the smallest number of transactions in all circumstances. However, it may be that that's not required for the best answer (best, in this case, meaning maximum "bang per buck"). It may be that even the basic 1/2/3 rule set will give you a good-enough answer for your purposes.

    0 讨论(0)
  • 2020-11-30 19:21

    You should be able to solve this in O(n) by first determining how much each person owes and is owed. Transfer the debts of anyone who owes less than he is owed to his debtors (thus turning that person into an end point). Repeat until you can't transfer any more debts.

    0 讨论(0)
提交回复
热议问题