ala*_*ode 11 language-agnostic algorithm
我最近被要求计算一起去旅行的一群人所欠的钱,并且遇到了一个有趣的问题:假设你知道每个人欠另一个人的金额,那么巩固人与人之间债务的一般算法是什么?这样只需要支付最少的款项?以此为例:
我们可以通过重新制定这样的债务来取消迈克和约翰之间的付款:
我手工完成了数学计算,因为它很容易,但是后来我的程序员很想找到一个通用的算法来为一个任意大的组做这个.这对我来说似乎是一个图算法,所以我将其重新表示为图:
And*_*erd 15
我的意见是:你让这个过于复杂.
把它看成是钱的"池",完全失去了关系:
代替:
算法只需要思考:
净化这个:
将其分为"给予者"和"接收者"列表.列表中的每个给予者将通过接收者列表,为每个接收者提供他们需要的东西,直到给予者为止.当接收器收到他们需要的所有东西时,他们就会从列表中删除.
稍后编辑
正如其他海报所观察到的那样,这简化了问题.但是,"给予者"和"接收者"列表可能存在最佳排序,但我们尚未找到确定此排序的直接方法.
仅仅弄清楚接收器和提供者是不够的.虽然我认为这种策略是在正确的轨道上,但它也无法确保算法找到尽可能少的支付金额.
例如,
虽然很明显这可以用3个支付(A和C到D,B到E)来完成.我想不出一个能满足所有问题集的高效算法.
更好的例子,
如果我们采用贪婪的方法将人D付给F,我们最终会得到次优解,而不是最优解(A&D到E,B&C到F).
这个问题与Bin Packing问题有很多相似之处,而Bin Packing问题已被证明是NP难的.唯一的区别是我们有多个不同大小的箱子以及所有箱子中的总空间等于所有物品的总大小的条件.这让我相信这个问题很可能是NP难的,但是在增加的约束条件下,它可能在多项式时间内得到解决.
虽然我同意@Andrew 的观点,认为将其转化为图形问题可能过于复杂,但我不确定他的方法会产生最少的交易数量。这就是你在现实生活中解决问题的方法,以免让自己头疼。只是集中钱。
一些看似“正确”的步骤:
与往常一样,恐怕我对前两个步骤相当确定,但对其他步骤不太确定。无论如何,这听起来确实像是教科书上的问题。我确信那里有一个“正确”的答案。
在企业财务领域,这被称为支付或结算净额结算。
跨国公司通常每个月在其子公司之间有大量的资金流动,而且通常以不同的货币进行。通过优化这些流量的结算,他们可以节省大量资金。通常,公司每月执行一次此类优化(净额结算周期)。当存在多种货币时,储蓄来源有以下三种:
有两种方法可以实际计算优化沉降。
双边净额结算是 @AndrewShepherd 在本页上详细描述的解决方案。然而,在跨境实施中,这种方法可能会产生法律和行政问题,因为每个月都会跨越不同的边界。
多边净额结算通过添加一个称为净额结算中心的新子公司来解决网络问题,并通过它重新路由所有金额。比较之前和之后的图如下:
结网前

结网后

虽然这增加了不必要的流量(与双边净额结算相比),但优点是:
(在基本层面上,计算很简单,但可能存在许多法律和行政复杂性,因此企业经常从软件供应商或服务提供商处开发或购买净额结算系统。)