На самом деле это похоже на работу, с которой могла бы помочь концепция двойной записи.
Ваши транзакции могут быть структурированы как бухгалтерские записи следующим образом:
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
И вот оно у тебя. При каждой транзакции вы кредитуете один счет в ГК и дебетуете другой, так что остаток всегда равен нулю. В конце вы просто отрабатываете минимальное количество транзакций, которое будет применено к каждой учетной записи, чтобы вернуть его в ноль.
В этом простом случае это простой перевод в 4 доллара от Билла к Алисе. Вам нужно уменьшить хотя бы одну учетную запись (но предпочтительно две) до нуля для каждой добавленной транзакции. Допустим, у вас было более сложное:
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
Тогда необходимые транзакции будут:
Bill -> Alice $4 0 1- 1 0
Bill -> Charles $1 0 0 0 0
К сожалению, в некоторых штатах эта простая жадная стратегия не дает наилучшего решения (спасибо j_random_hacker
за указание на это). Один пример:
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
Ясно, что это можно изменить за четыре хода (так как четыре шага - это все, что нужно, чтобы добраться туда), но, если вы выберете свой первый ход неразумно (Edie->Bill $2)
, пять - это минимум, с которым вам сойдет. *
Вы можете решить эту конкретную проблему с помощью следующих правил:
- (1), если вы можете уничтожить два баланса, сделайте это.
- (2) в противном случае, если вы можете стереть один баланс и настроить себя, чтобы стереть два в следующем ходу, сделайте это.
- (3) в противном случае уничтожить любой баланс.
Это приведет к следующей последовательности:
- (a) [1] не применимо, [2] может быть достигнуто с
Alan->Bill $5
.
- (b) [1] можно сделать с помощью
Chas->Bill $20
.
- (c) и (d), аналогичные рассуждения с Дагом, Эди и Фредом, для четырех полных ходов.
Однако это работает просто из-за небольшого количества возможностей. По мере того, как число людей увеличивается, а групповые взаимоотношения становятся более сложными, вам, скорее всего, понадобится исчерпывающий поиск, чтобы найти минимальное количество требуемых ходов (в основном правила 1, 2 и 3 выше, но расширенные для обработки большей глубины) .
Я думаю, это то, что потребуется, чтобы дать вам наименьшее количество транзакций при любых обстоятельствах. Тем не менее, может оказаться, что это не требуется для ответа best (лучший в данном случае означает максимальный «удар за доллар»). Вполне возможно, что даже базовый набор правил 1/2/3 даст вам достаточно хороший ответ для ваших целей.