Algorithm 等于或超过给定数字的所有组合
这与换硬币问题不同 给定一个dictAlgorithm 等于或超过给定数字的所有组合,algorithm,language-agnostic,combinations,subset-sum,Algorithm,Language Agnostic,Combinations,Subset Sum,这与换硬币问题不同 给定一个dictx=[a:1,b:2,c:1,d:3,e:2],我需要计算所有可能的键组合,使与这些键相关的值之和刚好超过或等于给定值,比如5。仅超过5意味着,如果所选元素小于5,我们可以再添加一个元素,即使它超过5,但一旦我们超过或等于5,就不能再添加更多元素 有两个问题使我的方法复杂化- 请注意,有些值是重复的,例如1和2各出现两次,需要单独考虑 在这种情况下订购物品 订购事宜也是如此,[b,c,d],[b,d,c],[c,b,d],[d,b,c],[d,b,c],[d,
x=[a:1,b:2,c:1,d:3,e:2]
,我需要计算所有可能的键组合,使与这些键相关的值之和刚好超过或等于给定值,比如5。仅超过5意味着,如果所选元素小于5,我们可以再添加一个元素,即使它超过5,但一旦我们超过或等于5,就不能再添加更多元素
有两个问题使我的方法复杂化-
[b,c,d],[b,d,c],[c,b,d],[d,b,c],[d,b,c],[d,c,b]
均单独包含在内。理想情况下,只有当我们超过5时,排序才重要,只要总和正好是5,排序就不重要
因此,上述问题的一些解决方案是使用和7的[a,b,c,d]
,使用和6的[a,b,c,e]
,使用和6的[b,c,d]
,使用和5的[d,e]
,等等
我如何处理这个问题。我曾考虑使用硬币兑换的输出,然后在每个结果列表中添加一个元素,但这并不能涵盖所有情况
编辑1:确定问题框架的更好方法可能是找到所有组合,使总和(i)等于5或(ii)刚好超过5,直到最后一个元素小于5,因此添加最后一个元素使其大于5。一旦我们有5个或>5个,就不会添加额外的元素
编辑2:澄清订购问题。为了提供一点上下文,键是设备,值是它所需要的资源。可用资源总量为5。并且设备根据其密钥分配资源,即首先服务第一个密钥-值对(按照密钥字母顺序排序)。对于b
,它需要2个,但假设只有1个资源可用-它将被分配1个,其余1个将在下一次运行中分配(溢出)。因此,当总和正好为5时,顺序并不重要,因为每个人都得到了自己想要的东西,并且不会溢出到下一个插槽。例如,ed
和de
意味着两者都得到了他们想要的东西,因此它们都应该被包括在内。
但是对于仅仅由于添加了最后一个元素而超过5的列表,排序问题只会对最后一个元素产生溢出效应。例如,
dce
表示d和c分别得到3和1,E只得到1(1溢出到下一次运行)。类似地,ced
意味着c和d分别得到1和3,溢出效应发生在d上,因为它只得到1。我认为这样改变换币算法可以解决问题
import itertools
def subset_sum(numbers, target, partial=[]):
exceed = sum([ v for k, v in partial[:-1]])
s = sum([ v for k, v in partial])
if exceed >= target:
return
elif s == target:
print (partial,sum([ v for k, v in partial]), target)
elif s > target:
print("print all permutation")
p = list(itertools.permutations(partial))
for state in p:
legit = sum([v for k, v in state[:-1]])
if (legit < target):
print(state)
for i in range(len(numbers)):
k, v = numbers[i]
remaining = numbers[i+1:]
subset_sum(remaining, target, partial + [(k,v)])
if __name__ == "__main__":
subset_sum([('a',1),('b',2),('c',1),('d',3),('e',2)],5)
导入itertools
def subset_sum(数字、目标、部分=[]):
超过=总和([v代表k,v代表部分[:-1]]
s=总和([v代表k,v代表部分])
如果超过>=目标:
返回
elif s==目标:
打印(部分,求和([v代表k,v代表部分]),目标)
elif s>目标:
打印(“打印所有排列”)
p=列表(itertools.置换(部分))
对于p中的状态:
legit=总和([v代表k,v处于状态[:-1]])
如果(合法<目标):
打印(状态)
对于范围内的i(len(数字)):
k、 v=数字[i]
剩余=数字[i+1:]
子集_和(剩余,目标,部分+[(k,v)])
如果名称=“\uuuuu main\uuuuuuuu”:
子集和([('a',1),('b',2),('c',1),('d',3),('e',2)],5)
更新的答案
关于需求的更多细节已添加到问题中。我认为这个版本与他们相符。但是没有指定预期的输出结构,因此这是一个猜测。它最终会得到如下一系列结果:
{首字母:{a:1,b:2,c:1},末字母:{d:3}
或者像这样:
{initial:{b:2,c:1,e:2}
它通过首先使用函数partitions
查找初始值的所有子集及其补码来实现<代码>分区(['a','b','c','d'])将有16个元素,包括[[a','b','d'],['c']]
,[[b','d'],['a','c','d']
和[[],['a','b','c','d']]
然后,对于每个分区,如果其左半部分的和等于目标,我们将其包括在内。如果总和小于目标值,我们将在右半部分的每个值中包含一个结果,使我们超过目标值
下面是一个Javascript实现:
//实用程序函数
const last=(xs)=>
xs[xs.length-1]
常量分区=(xs)=>
xs.length==0
? [[[], []]]
:分区(xs.slice(0,-1)).flatMap([p,q])=>[
[p,last(xs)],q],
[p,[…q,last(xs)]]
])
//辅助函数
常量总计=(xs)=>
x.reduce((a[k,v])=>a+v,0)
//主要功能
const sumTo=(n,xs,parts=分区(xs))=>
parts.flatMap(([incl,excl],[uuu,[uuuuu,t=total(incl))=>[
…(t==n?[{initial:incl}]:[]),
…(tv+t>n)
.map(e=>({首字母:incl,last:[e]}))
: []
)
])
//公共职能
常量子类=(n,dict)=>
sumTo(n,Object.entries(dict))
.map({initial,last})=>({
首字母:Object.fromEntries(首字母),
…(last?{last:Object.fromEntries(last)}:{})
}))
//样本数据
常量dict={a:1,b:2,c:1,d:3,e:2}
//演示
console.log(subsetSum(5,dict))
.as console wrapper{max height:100%!important;top:0}
您需要它是正确的,还是快速正确的?@b我想了解如何解决这个问题,所以它必须首先是正确的。一旦我有了一个工作代码,我将尝试看看如何使它变得更好