【发布时间】:2014-06-25 21:53:16
【问题描述】:
我的问题是:我想找到m 可能数字的所有n 长度组合,使得数字的平均值大于阈值X。
例如,假设长度为n=3,数字为{1, 2},阈值为1.5。允许的总组合为 2*2*2 == 2**3 = 8 即
222 - avg 2.000000 > 1.500000 -> include in acceptable set
221 - avg 1.666667 > 1.500000 -> include in acceptable set
212 - avg 1.666667 > 1.500000 -> include in acceptable set
211 - avg 1.333333 < 1.500000 -> adding 1 and below to the exclude list
122 - avg 1.666667 > 1.500000 -> include in acceptable set
121 - avg 1.333333 < 1.500000 -> skipping this vote combo
112 - avg 1.333333 < 1.500000 -> skipping this vote combo
111 - avg 1.000000 < 1.500000 -> skipping this vote combo
final list of valid votecombos
[[2, 2, 2], [2, 2, 1], [2, 1, 2], [1,2,2]]
我认为,解决这个问题的方法是想象一棵包含所有可能组合的树,然后动态修剪树以获得不可能的解决方案。例如想象n=3这样的级别树
root
/ \
1 2
/ \ / \
1 2 1 2
/ \ / \ / \ / \
1 2 1 2 1 2 1 2
到叶子的每条路径都是一个可能的组合。正如您可以想象的那样,n=3 和 m=5 级别的节点数约为 N == m**n == 5**3 == 125' nodes. Its easy to see that the tree gets really really large even form=5andn=20`。 96 万亿个节点。所以树不能存储在内存中。但它也不必如此,因为它非常结构化。
获得所有可能的有效组合的方法是通过 DFS 以一种预先排序的方式遍历树,但在遍历的同时继续修剪树。例如,在上面的示例中,前三个组合{222, 221, 212} 有效,但 211 无效。这也意味着任何其他包含两个 1 的 从那时起 的组合都将无效。所以我们几乎可以用根 1 修剪树的整个左侧,除了 122 !这将有助于我们避免检查 3 种组合。
为此,我编写了一个简单的 python 脚本
import string
import itertools
import numpy as np
import re
chars = '21'
grad_thr = 1.5
seats = 3
excllist = []
validlist = []
for word in itertools.product(chars, repeat = seats):
# form the string of digits
votestr = ''.join(word)
print (votestr)
# convert string into list of chars
liststr = list(votestr)
#print liststr
# map list of chars to list of ints
listint = map(int, liststr)
if len(list(set(listint) & set(excllist))) == 0:
# if there are no excluded votes in this votecombo then proceed
# compute a function over the digits; func can be average/bayesian score/something else.
y_mean = np.mean(listint)
print 'avg %f' %y_mean
#y_bayes = bayesian score
if y_mean >= grad_thr:
# if function result is greater than grad threshold then save result to a list of valid votes
validlist.append(listint)
print 'geq than %f -> include in acceptable set' %grad_thr
elif y_mean < grad_thr:
# if function result is not greater than grad threshold then add logic to stop searching the tree further
# prune unnecessary part of the tree
if listint[-1] not in excllist:
excllist = [int(d) for d in range(listint[-1] + 1)]
print 'adding %d and below to the exclude list' %listint[-1]
else:
print '%d already present in exclude list' %listint[-1]
else:
print 'skipping this vote combo'
print '\nfinal valid list of votecombos'
print validvotelist
print 'exclude list'
print excllist
print '\n'
通过这种方式,我会遍历所有可能的组合并 跳过 以避免计算平均值。但是,在进入 for 循环后,我仍然会检查每个可能的组合。
是否可以根本不检查组合?即我们知道组合 121 不起作用,但是我们仍然必须进入 for 循环然后跳过组合。可以不做吗?
【问题讨论】:
-
为什么
n=4在您的第一个示例中?看起来你只接受长度为3的字符串。为什么122的平均值不是1.667? -
抱歉,已编辑 n=3
-
我还是想知道
122的位数的平均值是1.33,而且111的位数的平均值也是1.33...跨度> -
希望改正错误
-
我想到了一种不同的算法,它从 DFS 树根处最高数字的 n 个副本的多重集开始,并在每个 DFS 边缘减少一些数字。这导致有效的修剪。它将适用于任意数字集,但如果没有孔,它会更简单,因为这意味着孩子的总和总是比其父母少 1。