68 lines
2.1 KiB
Python
Executable file
68 lines
2.1 KiB
Python
Executable file
#!/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))
|