initial commit
This commit is contained in:
commit
cdca6df821
1 changed files with 68 additions and 0 deletions
68
splitbill.py
Executable file
68
splitbill.py
Executable file
|
|
@ -0,0 +1,68 @@
|
||||||
|
#!/usr/bin/env python3
|
||||||
|
from itertools import chain, combinations
|
||||||
|
from typing import Generator
|
||||||
|
|
||||||
|
balances = {
|
||||||
|
# "A": -20,
|
||||||
|
# "B": 10,
|
||||||
|
# "C": 3,
|
||||||
|
# "D": -43,
|
||||||
|
# should be possible with 3 transactions (A, B, C balance excactly)
|
||||||
|
"A": 50,
|
||||||
|
"B": -30,
|
||||||
|
"C": -20,
|
||||||
|
"D": -40,
|
||||||
|
}
|
||||||
|
balances["E"] = -sum(balances.values())
|
||||||
|
|
||||||
|
|
||||||
|
def find_zerosum_subgroups(
|
||||||
|
balances: dict[str, int],
|
||||||
|
) -> Generator[tuple[str, ...], None, None]:
|
||||||
|
for n in range(2, len(balances)):
|
||||||
|
for combination in combinations(balances, n):
|
||||||
|
if sum(balances[key] for key in combination) == 0:
|
||||||
|
yield combination
|
||||||
|
|
||||||
|
|
||||||
|
def solve_greedily(balances: dict[str, int]) -> dict[tuple[str, str], int]:
|
||||||
|
creditors = {}
|
||||||
|
debitors = {}
|
||||||
|
for k, v in balances.items():
|
||||||
|
if v > 0:
|
||||||
|
creditors[k] = v
|
||||||
|
else:
|
||||||
|
debitors[k] = v
|
||||||
|
|
||||||
|
txn = {}
|
||||||
|
while not all(value == 0 for value in chain(creditors.values(), debitors.values())):
|
||||||
|
for debitor, debit_value in sorted(debitors.items(), key=lambda x: x[1]):
|
||||||
|
for creditor, credit_value in sorted(
|
||||||
|
creditors.items(), key=lambda x: x[1], reverse=True
|
||||||
|
):
|
||||||
|
sum_value = credit_value + debit_value
|
||||||
|
if abs(debit_value) <= credit_value:
|
||||||
|
del debitors[debitor]
|
||||||
|
creditors[creditor] = sum_value
|
||||||
|
txn[debitor, creditor] = abs(debit_value)
|
||||||
|
else:
|
||||||
|
debitors[debitor] = sum_value
|
||||||
|
del creditors[creditor]
|
||||||
|
txn[debitor, creditor] = credit_value
|
||||||
|
break
|
||||||
|
|
||||||
|
return txn
|
||||||
|
|
||||||
|
|
||||||
|
def solve(balances: dict[str, int]) -> dict[tuple[str, str], int]:
|
||||||
|
possibilities = []
|
||||||
|
for subgroup in find_zerosum_subgroups(balances):
|
||||||
|
txn_sub = solve({k: balances[k] for k in subgroup})
|
||||||
|
txn_other = solve({k: balances[k] for k in balances if not k in subgroup})
|
||||||
|
possibilities.append(txn_sub | txn_other)
|
||||||
|
if not possibilities:
|
||||||
|
possibilities.append(solve_greedily(balances))
|
||||||
|
return min(possibilities, key=lambda x: len(x))
|
||||||
|
|
||||||
|
|
||||||
|
print(solve(balances))
|
||||||
Loading…
Add table
Add a link
Reference in a new issue