Колективно оплатити проблему рахунку


23

За столом є людей. й людина повинна платити доларів.i p inipi

Деякі люди не мають правильних рахунків точно платити , тому вони придумують наступний алгоритм.pi

По-перше, кожен кладе частину своїх грошей на стіл. Потім кожна особа забирає гроші, які переплатив.

Рахунки мають фіксований набір номіналів (не частина вхідних даних).

Приклад: Припустимо, є двоє людей, Аліса та Боб. Аліса заборгувала 5 доларів і має п'ять рахунків у розмірі 1 долара . Боб заборгував 2 долари і має один рахунок 5 доларів . Після того, як Аліса і Боб поклали всі свої гроші на стіл, Боб забирає назад 3 долари , і всі радіють.

Звичайно, бувають випадки, коли не потрібно класти всі свої гроші на стіл. Наприклад, якщо в Аліси було тисячі доларів за 1 долар , їй не потрібно покласти їх на стіл, а потім забрати більшість з них назад.

Я хочу знайти алгоритм із такими властивостями:

  1. Вхід вказує кількість людей, скільки кожна людина заборгувала і скільки рахунків у кожному купюрі кожна людина.

  2. Алгоритм повідомляє кожній людині, які рахунки потрібно поставити на стіл у першому раунді.

  3. Алгоритм повідомляє кожній людині, які рахунки потрібно видалити зі столу у другому раунді.

  4. Кількість купюр, поданих на стіл + кількість купюр, вилучених зі столу, зведена до мінімуму.

Якщо неможливого рішення, алгоритм просто повертає помилку.


9
Є номіналів банкнот фіксованою заздалегідь (скажімо , до американського номіналів $ 1, $ 2, $ 5, $ 10, $ 20, $ 50 і $ 100), або частина вхідного? Іншими словами, чи повинен алгоритм вирішувати можливість того, що Мефістофель має три рахунки в розмірі 7 доларів США, банкноти в розмірі 13 доларів США та п'ятнадцять рахунків у розмірі 4 доларів США ?
JeffE

1
Рахунки фіксовані. Я думаю, що в цьому випадку я не можу зменшити суму підмножини і довести, що це NP-Hard. Я його відредагую.
Чао Сю

1
Вам потрібен спосіб виразити 4/5 як єдину оптимізацію. Оптимізувати ці дві незалежні умови неможливо. Я знаю про те, що ви маєте намір, у мене була аналогічна проблема і раніше, але вам потрібно точно визначити, що означає оптимізувати для обох умов.
edA-qa mort-ora-y

3
Я думаю, що було б краще, як вихідний, припустити, що або кожен платить рахунок точно, або алгоритм просто повідомляє про помилку.
JeffE

2
Яке саме тут питання, чи є вимоги щодо складності? Написання наївного алгоритму здається тривіальним, чи я щось пропускаю?
Стефан Гіменез

Відповіді:


6

Якщо ви перестановите проблему дещо іншим (але еквівалентним) способом, алгоритм стає більш очевидним:

Є залучених сторін: люди, і один restauarant. Нехай - це сума грошей, яку повинна мати після закінчення та оплати їжі. Наприклад, якщо Аліса $ 36 і заборгував $ 25, Боб має $ 12 і повинен $ 11, і Карл має $ 30 і заборгував $ 25, ми говоримо , що є ресторан і є:nn1piip0

p=(61,11,1,5)

Тобто, коли їжа закінчиться, ресторан повинен мати 61 долар , Аліса - 11 доларів , у Боба - 1 долар, а в Карла - 5 доларів .

Тепер дозвольмо перерахувати всі рахунки. Наприклад:bm

b=(1,5,10,20,1,1,5,5,10,20)

Номінали векселів не мають значення, але я вибрав номінали паперової американської валюти для цього прикладу, оскільки вони знайомі.

Ми прагнемо мінімізувати кількість рахунків, які змінюють руки, тому ми пов'язуємо "вартість" з особою, яку залишаю, з рахунком , використовуючи матрицю . Записи 0 у цій матриці вказують, з яких рахунків починається кожна сторона ( для всіх оскільки ресторан починається без рахунків).ij{0,1}CC0,j=0j

Продовжуючи наш приклад:

C=[0000000000000011111111110000111111111100]

вказує на те, що Аліса починала з $ 1, $ 5, $ 10, $ 20, Боб починав з $ 1, $ 1, $ 5, $ 5, а Карл починав з $ 10 і $ 20.

Знову ж таки, мета - мінімізувати кількість рахунків, які змінюють руки. Іншими словами:

Minimize:i=0n1j=0m1Ci,jxi,jsubject to:i=0n1xi,j=1 for 0j<m,j=0m1xi,jbj=pi for 0i<n,andxi,j0

Перше обмеження говорить про те, що рішення може призначити певний вексель лише одній стороні, а друге забезпечує, щоб усі сплатили відповідну суму.

Це проблема 0,1 ІНТЕГЕРНОГО ПРОГРАММУВАННЯ і є NP-завершеною (див. [ Karp 1972 ]). На сторінці Вікіпедії про лінійне програмування є інформація про різні алгоритми, які можна використовувати для таких типів проблем.

Є потенційно безліч оптимальних рішень; від руки першим рішенням прикладу, який я придумав, було:

x=[0101100111101000000000001000000000001000]

що означає Аліса платить рівно $ 5 і $ 20, Боб платить рівно $ 1, $ 5 і $ 5, і Карл переплачує $ 10 і $ 20 , а потім видаляє $ 5 з таблиці.

Я також використав змішаний модуль Integer лінійного програмування в Sage Math системи , яка має можливість використовувати різні движки решателя ( GLPK , МОНЕТІ , CPLEX або Gurobi ). Перше рішення, яке воно дало, було

x=[0101010111101000000000001000000000000100]

що майже те саме, за винятком того, що Карл взяв "інші" 5 доларів, які Боб поклав на стіл.

Формулювання задачі таким чином задовольняє всі перелічені вами властивості (ви можете екстраполювати, які рахунки закінчуються з і матриця рішення ). Виняток - можливо, №4, про який йшлося в коментарях до питання. Мені незрозуміло, що ви хотіли б зробити в ситуації, коли не існує можливого рішення набору лінійних рівнянь:xCx

Визначте підмножину людей, які можуть сплатити зменшену суму? Або, можливо, підмножина людей, які все-таки могли оплатити весь рахунок, тобто вони платять за свого друга.

У вашій остаточній заяві здається, що ви зацікавлені у тому випадку, коли номінали векселів виправлені, проте це не змінить проблеми.

У будь-якому випадку, є також рішення в якому кожна людина оплачує кредитну карту.O(1)


Що ця проблема може бути виражена через те, що IP було (майже?) Зрозумілим; але наскільки добре це рішення? Чи можна IP-адреси створеної форми ефективно вирішувати? Якщо ні, чи існує швидший алгоритм?
Рафаель

Існує більш стисла форма цього ІС, яка має змінну для кількості векселів певного номіналу, ніж змінна 0,1. Фіксовані номінали мало змінюють складність, якщо кількість людей також фіксована, алгоритм Ленстра може вирішити це в поліноміальний час.
Чао Сю

-2

Безумовно, деякими базовими стартами може бути включення найменших наявних рахунків, щоб досягти загальної суми загального рахунку. Якщо вам не бажання дозволити рахунки в розмірі 2 доларів, кожна людина може просто зняти найбільшу купюру, яку може взяти з пулу, і потрапить туди відносно швидко. Рахунок у розмірі 2 доларів відміняє це, оскільки він не поділяється добре на інші номінали та значно ускладнює проблему. Звичайно, існує ряд інших оптимізацій, які можна зробити, щоб зробити спостереження щодо необхідності додаткових коштів, що додаються під час першого раунду (наприклад, якщо загальна кількість рахунків у розмірі 1 долара колись достатня для покриття рахунку, то всі може припинити подачу, якщо вони ще не внесли достатньо коштів для свого рахунку).

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.