Python 在最大化最低权重的同时,使用因子均匀分割数字的算法
给定一个数字和一系列因素,将该数字拆分为其给定因素以最大化最小权重(权重是特定因素的倍数)的最有效方法是什么 另一种说法是:Python 在最大化最低权重的同时,使用因子均匀分割数字的算法,python,algorithm,math,Python,Algorithm,Math,给定一个数字和一系列因素,将该数字拆分为其给定因素以最大化最小权重(权重是特定因素的倍数)的最有效方法是什么 另一种说法是: 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 facto
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
给定:
w1*f1+w2*f2+…+wN*fN=Z
哪里:
给定f1、f2、f3…fN是a的升序因子
给定正数Z
找到:w1,w2,w3…wN,它们是对应因子的非零正权重和
近似均匀分布的重量
例子
e、 g.给定:a+2b+4c=32,求出最大可能的a,b,c
1 2 4
a、b、c
32 00 00
00 16 00
00 00 08
08 04 04
06 05 04可能的方法:好的溶液应含有一些重量相等的部分
从可能的最大重量开始,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
(可能是具有最不同因素的变体),而我认为解决方案(未在您的示例中列出)45
也相当不错
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
实现@MBo应答(在他告诉我逻辑时选择他的应答)。如果我错过了一个用例,请随意评论(我故意不考虑减少k
,因为此函数的目的是为给定的一组因子获得最大最小权重)
谢谢,你能再举一个例子吗。。我不明白你是如何从
4 4 5
中得到4 4 5
?你错过了这个变体:4*1+4*2+5*4
谢谢,我知道了。。。但是想弄清楚这是一种算法还是一种基本的因式分解?当你说1+1+1+1
时,你的意思是(1+1)=>8+1=>4+1=>4
。这种方法可以减少问题的规模(如果可能的话)。大约1个-是的,我们已经有了4*1+4*2+4*4
并添加了4个1以获得8*1+4*2+4*4
谢谢,但我可能在这方面仍然很慢:(如果你能再举一个例子,一步一步地展示它,那就太好了:对于1,2,8个因子来分割一个32,我看到:1+2+8=11 Kmax=32/11=2 Rest=32%11=10,现在取最高的一个:2 7 2,这个逻辑也适用于大量的因子吗?
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
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]
>>>