可以使用背包问题解决方法(尺寸不一的背包)解决此问题吗?

时间:2019-05-17 04:30:26

标签: algorithm optimization dynamic-programming knapsack-problem

为遵守法规,银行需要确保其持有的资金中至少90%(或其他固定比例)是“干净的”。

如果货币在“干净”帐户中,则被认为是干净的。如果帐户中的所有资金均来自可验证来源,则被视为“干净”。

银行可以强制将钱从无法验证的来源退还给客户,以增加“干净”钱的比例,以符合法规要求。问题是要确定银行需要返还的最低金额以符合规定。

Account Verif   NonVerif    Divi    Clean   NotClean
1   889.77  157.01  5.67    0   1046.78
2   907.88  160.21  5.67    0   1068.09
3   1187.18 209.5   5.67    0   1396.68
4   918.12  162.02  5.67    0   1080.14
5   1721.88 303.86  5.67    0   2025.74
6   828.17  276.05  3.00    0   1104.22
7   1127.6  375.86  3.00    0   1503.46
8   1177.13 392.37  3.00    0   1569.5
9   801.81  267.27  3.00    0   1069.08
10  741.9   247.3   3.00    0   989.2
11  0   1468.11 0.00    0   1468.11
12  0   853.66  0.00    0   853.66
13  2354.81 0   -1.00   2354.81 0
14  2267.1  0   -1.00   2267.1  0
15  2238.3  0   -1.00   2238.3  0
16  2188.66 0   -1.00   2188.66 0
17  2167.85 0   -1.00   2167.85 0
18  2166.1  0   -1.00   2166.1  0
19  2165.59 0   -1.00   2165.59 0
20  2163.84 0   -1.00   2163.84 0
21  2145.43 0   -1.00   2145.43 0
22  2117.76 0   -1.00   2117.76 0
23  1320.26 0   -1.00   1320.26 0
24  1299.99 0   -1.00   1299.99 0
25  1241.02 0   -1.00   1241.02 0
26  1237.36 0   -1.00   1237.36 0
27  1208.74 0   -1.00   1208.74 0
28  1114.58 0   -1.00   1114.58 0
29  1048.63 0   -1.00   1048.63 0
30  1010.92 0   -1.00   1010.92 0
31  971.1   0   -1.00   971.1   0
32  874.95  0   -1.00   874.95  0
33  832.01  0   -1.00   832.01  0
34  825.72  0   -1.00   825.72  0
TOTAL   45262.16    4873.22     34960.72    15174.66

在上面的示例中,银行持有的总金额为34960.72 + 15174.66 = 50135.38;无需进行任何清洗,只有69.7%(34960.72 / 50135.38 = 0.697 ...)被认为是清洗的,因此银行需要清洗以符合规定。

如果银行清理了前两个帐户,则银行持有的总金额将为50135.38-157.01-160.21 = 49818.16,清洁货币将为34960.72 + 889.77 + 907.88 = 36758.37;清洁货币的比例将是36758.37 / 49818.16 = 73.7%。

在上面的示例中,Div = Verif / NonVerif(“ Verif”为值,“ NonVerif”为“ Weight”,以查看提供最佳比率的项来选择它们);示例中的列表按Div降序排序。天真的方法是按顺序选择要清理的帐户,直到银行遵守规定为止。

我当时正在考虑使用Avikalp Srivastava here建议的方法:因此将Verif(值)视为权重,将NonVerif(成本)视为值;然后使用常规的背包问题解决方法来查找在Verif保持> = 90%*(银行持有的总金额)时可以消除的最大成本;问题是,当您向背包中添加不干净的物品时,银行持有的总金额会减少,因为银行正在将这笔钱退还给客户(这样,随着更多物品的添加,背包会变小吗?)。蛮力导致显示的数据出现内存溢出。我实际上试图解决这个问题数小时,而没有找到答案。也许背包问题解决方法不是解决此问题的正确方法(?)

天真的方法足以满足我的目的,但我仍然想了解如何正确解决它。

2 个答案:

答案 0 :(得分:1)

一个想法可能是对目标未验证量进行二进制搜索以返回。然后,对于每个这样的候选人,运行一个背包,其中那个候选人是最大权重,每个未验证的金额都是权重,要最大化的值是帐户中的可验证金额。 (当然,我们只需要查询未验证资金的帐户即可。)

答案 1 :(得分:1)

注意:此方法基于我在上面的注释中的理解。如果我的理解有误,我将进行编辑。

这是一种基于整数线性规划(ILP)的方法。

  • I是所有帐户的集合,而让I_cI_n分别是干净帐户和非干净帐户的集合。
  • V[i]NV[i]为帐户i的可验证资金和不可验证资金。
  • r为必须清理的资金比例(例如90%)。

(这些是参数-模型的输入。)

  • 如果我们清理帐户x[i] = 1,让ii中的I_n,否则为0。 (我们不会清除I_c中的帐户。)

(这是一个二进制决策变量-模型将为其设置值的变量。)

那么ILP是:

minimize sum {i in I_n} NV[i] * x[i]
subject to sum {i in I_c} V[i] + sum {i in I_n} V[i] * x[i] >= 
               r * (sum {i in I} (NV[i] + V[i]) - sum {i in I_n} NV[i] * x[i]))
           x[i] in {0,1} for all i in I_n

目标函数使清洗的总资金最小化。 (对于i中的每个I_n,如果我们清洗帐户,那么我们将清除NV[i]的金额。)第一个约束条件是,总清洗货币必须至少为0.9总金额中的总金额:总净额是原始净额(sum {i in I_c} V[i])加上新净额(sum {i in I_n} V[i] * x[i]);总金额等于原始总金额(已验证并未经验证)减去已清理的资金。第二个约束只是说所有x[i]变量必须是二进制的。

在实现方面,您当然可以在Excel / Solver中解决此问题。 (我怀疑您所获得的非线性是因为您编写约束的方式更像是

sum {i in I_c} V[i] + sum {i in I_n} V[i] * x[i] / (sum {i in I} (NV[i] + V[i]) - sum {i in I_n} NV[i] * x[i])) >= r

这是非线性的。)您还可以使用Python / PuLP或任意数量的其他线性编程包。