将一个偶数分成N份,每份都是2的倍数

Dividing an even number into N parts each part being a multiple of 2

假设我有数字 100,我需要将其分成 N 个部分,每个部分最初不应超过 30。所以最初的分组是 (30,30,30)。余数(即 10)将通过连续向每组加 2 来分配给这三组,从而确保每组都是 2 的倍数。因此,所需的输出应类似于 (34,34,32)。

注意:原来的数总是偶数。

我尝试在 Python 中解决这个问题,这就是我想到的。很明显,它没有按照我想象的方式工作。它通过向每个组迭代地添加 1(而不是 2,根据需要)来分配余数。

num = 100
parts = num//30  #Number of parts into which 'num' is to be divided

def split(a, b):
  result = ([a//b + 1] * (a%b) + [a//b] * (b - a%b))
  return(result)

print(split(num, parts))

输出:

[34, 33, 33]

期望的输出:

[34, 34, 32]

简化问题:忘记 2 的倍数

首先,让我们先简化一下您的问题。忘掉 2 的倍数吧。假设你想将一个非偶数 n 分成 k 个非偶数部分。

显然,最平衡的解决方案是让某些部分为 n // k,而某些部分为 n // k + 1

其中有多少?我们称 rn // k + 1 的零件数。然后有k - r个部分n // k,所有部分加起来为:

   (n // k) * (k - r) + (n // k + 1) * r
== (n // k) * (k - r) + (n // k) * r + r
== (n // k) * (k - r + r) + r
== (n // k) * k + r

但是这些部分总和应该是 n,所以我们需要找到 r 这样:

n == (n // k) * k + r

幸运的是,您可能会在这里认出欧氏除法,n // k 是商,r 是余数。

这给了我们 split 函数:

def split(n, k):
    d,r = divmod(n, k)
    return [d+1]*r + [d]*(k-r)

测试:

print( split(50, 3) )
# [17, 17, 16]

拆分成 2 的倍数

现在回到您的 split_even 问题。现在我们有了通用函数 split,解决 split_even 的一个简单方法是使用 split:

def split_even(n, k):
    return [2 * x for x in split(n // 2, k)]

测试:

print( split_even(100, 3) )
# [34, 34, 32]

概括:m

的倍数

用除 2 以外的数字 m 的倍数做同样的事情是微不足道的:

def split_multiples(n, k, m=2):
    return [m * x for x in split(n // m, k)]

测试:

print( split_multiples(102, 4, 3) )
# [27, 27, 24, 24]

我这里的方法是创建三个数组并对它们求和,前两个很简单,但最后一个有点复杂 - 它只是重复 2 (by) 尽可能多的次数给定余数, 然后重复 0s.

# Part 1
np.repeat(first, x//first) 
# Part 2
np.repeat(by, x//first)
# Part 3
np.repeat([by, 0], [(x//first) - ((x - (x//first*first)) // by % by), (x - (x//first*first)) // by % by])

包装成函数:

def split(x, first, by):
  return(np.repeat(first, x//first) + np.repeat(by, x//first) + np.repeat([by, 0], [(x//first) - ((x - (x//first*first)) // by % by), (x - (x//first*first)) // by % by]))

split(100, 30, 2)

这个解决方案不是很清楚也很容易理解,但它不需要任何循环。

完整代码:

def split(a,b):
     lower = (a//b//2) * 2
     num = a % (b*2) // 2
     return [lower + 2] * num + [lower] * (b - num)

解释:

  • 首先获取所有部分的值:我们将除法的结果(value // parts)四舍五入到下一个偶数((x // 2) * 2)
  • 要获得更高值的个数:我们使用 a 除法的余数,将其除以 2 以补偿乘法
  • last:较高的数字只是较高值的计算数量的 lower + 2 倍,较低的数字正在填充其他空间