c# – 子集和算法效率
我们每天都有许多付款(交易)进入我们的业务.每笔交易都有一个ID和金额.我们要求将大量这些交易与特定金额进行匹配.例:
Transaction Amount 1 100 2 200 3 300 4 400 5 500 如果我们想要找到总计600的交易,你将拥有多个集合(1,2,3),(2,4),(1,5). 我发现了一个我已经适应的算法,其工作方式如下所述. 30次交易需要15ms.但是,交易数量平均约为740,最高接近6000.这是一种更有效的方式来执行此搜索吗? sum_up(TransactionList,remittanceValue,ref MatchedLists); private static void sum_up(List<Transaction> transactions,decimal target,ref List<List<Transaction>> matchedLists) { sum_up_recursive(transactions,target,new List<Transaction>(),ref matchedLists); } private static void sum_up_recursive(List<Transaction> transactions,List<Transaction> partial,ref List<List<Transaction>> matchedLists) { decimal s = 0; foreach (Transaction x in partial) s += x.Amount; if (s == target) { matchedLists.Add(partial); } if (s > target) return; for (int i = 0; i < transactions.Count; i++) { List<Transaction> remaining = new List<Transaction>(); Transaction n = new Transaction(0,transactions[i].ID,transactions[i].Amount); for (int j = i + 1; j < transactions.Count; j++) remaining.Add(transactions[j]); List<Transaction> partial_rec = new List<Transaction>(partial); partial_rec.Add(new Transaction(n.MatchNumber,n.ID,n.Amount)); sum_up_recursive(remaining,partial_rec,ref matchedLists); } } 事务定义为: class Transaction { public int ID; public decimal Amount; public int MatchNumber; public Transaction(int matchNumber,int id,decimal amount) { ID = id; Amount = amount; MatchNumber = matchNumber; } } 解决方法
如前所述,您的问题可以通过O(n * G)中的伪多项式算法来解决,其中n个项目和G – 您的目标总和.
第一部分问题:是否有可能实现目标总和G.以下伪/ python代码解决了它(在我的机器上没有C#): def subsum(values,target): reached=[False]*(target+1) # initialize as no sums reached at all reached[0]=True # with 0 elements we can only achieve the sum=0 for val in values: for s in reversed(xrange(target+1)): #for target,target-1,...,0 if reached[s] and s+val<=target: # if subsum=s can be reached,that we can add the current value to this sum and build an new sum reached[s+val]=True return reached[target] 这个想法是什么?让我们考虑值[1,3,6]和目标总和7: >我们从空集开始 – 可能的总和显然为0. >作为最后一步,我们考虑6并获得{0,6,7}作为可能的总和. 但是你还需要导致目标总和的子集,为此我们只记得采用哪个元素来实现当前的子和.此版本返回一个子集,该子集导致目标总和,否则为None: def subsum(values,target): reached=[False]*(target+1) val_ids=[-1]*(target+1) reached[0]=True # with 0 elements we can only achieve the sum=0 for (val_id,val) in enumerate(values): for s in reversed(xrange(target+1)): #for target,0 if reached[s] and s+val<=target: reached[s+val]=True val_ids[s+val]=val_id #reconstruct the subset for target: if not reached[target]: return None # means not possible else: result=[] current=target while current!=0:# search backwards jumping from predecessor to predecessor val_id=val_ids[current] result.append(val_id) current-=values[val_id] return result 作为另一种方法,您可以使用memoization加速当前解决方案,记住状态(子项,number_of_elements_not考虑)是否可以实现目标总和.但我想说标准的动态编程在这里是一个不易出错的可能性. (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |