给出一个数字和一系列因素,将这个数字分成给定因子的最有效方法是什么,以便最大化最小权重(权重是特定因子的倍数)?
>>> number = 32
>>> given_factors = [1,2,4]
>>> evenly_split_a_number_with_factors(number, given_factors)
[6,5,4]
# note: 6*1 + 5*2 + 4*4 == 32
将其视为另一种方式:
Given:
w1*f1 + w2*f2 + ... + wN*fN = Z
Where:
given f1,f2,f3...fN are ascending order factors of a
given positive number Z
Find: w1,w2,w3...wN which are corresponding factors' non-zero positive weights and
weights being approximately evenly distributed
Example
e.g. Given: a + 2b + 4c = 32, find largest together possible a,b,c
1 2 4
a b c
32 00 00
00 16 00
00 00 08
08 04 04
06 05 04 <- should be the outcome of this algorithm
答案 0 :(得分:1)
可能的方法:好的解决方案应该包含一些权重相等的部分。
从最大可能的重量Kmax = N div SumOfFactors
开始,然后拆分数字的其余部分
如果无法进行分割 - 减轻重量并重复
这种方法试图减少问题的大小 - 这对于更大的求和次数和数量是很重要的。
对于您的示例 - 好的解决方案应该看起来像
32 = K * (1 + 2 + 4) + Split_of_(32 - 7 * K)
Kmax = 32 div 7 = 4
Rest = 32 - 4 * 7 = 4
Varitants of splitting rest 4 into factors:
4 = 4 gives weights 4 4 5
4 = 2+2 gives weights 4 6 4
4 = 2+1+1 gives weights 6 5 4
4 = 1+1+1+1 gives weights 8 4 4
最好的变种是2+1+1
(也许是最不同因素之一),而我认为解决方案(未在您的示例中列出)4 4 5
也非常好。
当KMax不合适的情况时:
120 into (2,7,11,19)
sum = 39, k=3, rest = 3, it is impossible to make 3
k=2, rest = 42, we can make partitions:
42=3*2+2*7+2*11, possible solution is 5,4,4,2
42=2*2+2*19, possible solution is 4,2,2,4
答案 1 :(得分:0)
实施@MBo回答(选择他的答案,因为他告诉我逻辑)。如果我错过了一个用例,请随意发表评论(我故意不考虑减少k
,因为此函数的目的是为给定的一组因子获得最大最小权重)
def evenly_weight_a_number_with_factors(number, factors):
"""
Args:
number (int): Number to evenly split using `factors`
factors (list): list of ints
>>> evenly_weight_a_number_with_factors(32, [1,2,4])
6,5,4
Given:
w1*f1 + w2*f2 + ... + wN*fN = Z
Where:
given f1,f2,f3...fN are ascending order factors of a
given positive number Z
Find: w1,w2,w3...wN which are corresponding factors' non-zero positive weights and
weights being approximately evenly distributed
Example
e.g. Given: a + 2b + 4c = 32, find largest together possible a,b,c
1 2 4
a b c
32 00 00
00 16 00
00 00 08
08 04 04
06 05 04 <- should be the outcome of this algorithm
"""
log = logging.getLogger(evenly_weight_a_number_with_factors_logger_name)
# function to return True if all numbers in `_factors` are factors of number `n`
are_all_factors = lambda n, _factors: all(n % f == 0 for f in _factors)
def weighted_sum(__weights, __factors):
return sum([wt*factor for wt, factor in zip(__weights, __factors)])
def add_variant_wt(__weights, i, _remainder_weight):
old__weights = __weights[:]
if _remainder_weight < factors[i]:
log.warn('skipping add_variant_wt _remainder_weight: {} < factor: {}'.format(_remainder_weight, factors[i]))
return []
variant_wt = _remainder_weight / factors[i]
variant_wt_rem = _remainder_weight % factors[i]
log.debug('add_variant_wt: weights, i, renainder_weight, variant_wt, remain: {}'
.format((__weights, i, _remainder_weight, variant_wt, variant_wt_rem)))
if variant_wt_rem:
__weights[i] += variant_wt
if i + 1 >= len(factors):
return add_variant_wt(__weights, i-1, variant_wt_rem)
return add_variant_wt(__weights, i+1, variant_wt_rem)
__weights[i] += variant_wt
log.debug('add_variant_wt i: {} before: {} after: {}'.format(i, old__weights, __weights))
return __weights
assert list(sorted(factors)) == factors, "Given factors {} are not sorted".format(factors)
assert are_all_factors(number, factors) == True, "All numbers in {} are not factors of number: {}".format(factors, number)
sum_of_all_factors = sum(factors)
largest_possible_weight = number / sum_of_all_factors
remainder_weight = number % sum_of_all_factors
variant_weight_sets = []
tmp_weights = []
for _ in factors:
tmp_weights.append(largest_possible_weight)
log.debug('tmp_weights: {} remainder_weight: {}'.format(tmp_weights, remainder_weight))
for i, _ in enumerate(factors):
_weights = add_variant_wt(tmp_weights[:], i, remainder_weight)
if _weights:
variant_weight_sets.append(_weights)
weights = variant_weight_sets[-1] # pick wt variance where largest factor gets the biggest weight
log.debug('variant_weight_sets: {}'.format(variant_weight_sets))
sum_weighted = weighted_sum(weights, factors)
assert sum_weighted == number, "sum_weighted: {} != number: {}".format(sum_weighted, number)
return weights
结果如下:
>>> evenly_weight_a_number_with_factors(32, [1,2,4])
[4, 4, 5]
>>> evenly_weight_a_number_with_factors(32, [1,2,8])
[2, 3, 3]
>>> evenly_weight_a_number_with_factors(32, [1,2,2])
[6, 6, 7]
>>> evenly_weight_a_number_with_factors(100, [1,2,4,4,100])
[0, 0, 0, 0, 1]
>>> evenly_weight_a_number_with_factors(100, [1,2,4,4])
[10, 9, 9, 9]
>>>