【问题标题】:Find nth occurence of groups of thousands which sum to a given number in lexical order查找第 n 次出现的数千组,它们按词汇顺序总和为给定数字
【发布时间】:2020-04-08 07:39:33
【问题描述】:

A previous question 要求按词汇顺序(从低到高)解决

a+b+c+d… = x

其中 a,b,c,d... 是 0-999 和 x 之间的任意整数 是固定整数

给出了一个答案,它使用 python 有效地完全计算了这个。

但是,对于非常大的数字,循环可能需要数年才能完成。

例如,巨大的数字:

304,153,525,784,175,759

x=2700 的解决方案,因为三组加起来等于2700

304+153+525+784+175+759 = 2700

但是,循环遍历算法以获得等于此数字的第 nth 个解决方案需要数月或数年。

有没有办法直接计算第 nth 解? IE。对于已知解,计算有多少解小于这个解。

【问题讨论】:

  • 第一个解决方案是什么?从n-th 解决方案到n+1-th 的规则是什么?
  • @HighPerformanceMark 不确定。在链接的问题中有一个循环算法。不知道如何将其分解为一个公式
  • 这是枚举组合学中的一个重要问题。您本质上是在要求一个 unrank 函数,该函数从一个等级(索引)到该等级的组合对象。 Mathematics 可能是一个更好的提问地点。
  • @JohnColeman 在那里尝试过。但他们不知道。它是一种非数学操作,所以 johanC 的解决方案可能是最好的解决方案

标签: math numbers partition


【解决方案1】:

这是一种查找解决方案索引的方法(或:有多少较小的解决方案)。代码分为两部分:

  • 找出给定总和x 的某个固定数量的组n 有多少解决方案。这是一个递归函数。基本上,对于n 组和求和x,对于从0 到999 的所有k,求和n-1 组和求和x-k 有多少个解。由于递归函数经常使用相同的值调用,结果存储在一个记忆字典中,以便下次立即使用。

  • 使用此函数计算存在多少较小的解决方案。这是一种类似的求和方式。例如。 6组,以304开头,计算有多少5组在303之后,总和为x-303,加上以302开头的5组数,总和为x-302等。然后以304,153为起点,求304,152之后有多少个4-groups,总和为x-304-152等。

这是完整的代码,测试了相当多的输入(由前面的程序生成的测试)。给定的 18 位数字只需要几秒钟。

grouping = 3
max_in_group = 10 ** grouping - 1
number_to_test = 304153525784175759  # number_to_test = '304,153,525,784,175,759'
d = {}  # dictionary for memoization

# count how many solutions there are for n groups summing to x, and each group being a number from 0 to max_in_group;
# when counting simple digit sums, n is the number of digits, and max_in_group should be 9;
# when counting in groups of thousands, n is the number of groups (digits / 3), and max_in_group should be 999
def count_digitsums(x, n, max_in_group=9):
    if not(0 <= x <= n * max_in_group):
        return 0
    elif n == 1:
        return 1
    else:
        if (x,n) in d:
            return d[(x,n)]
        s = 0
        for i in range(max_in_group+1):
            s += count_digitsums(x-i, n-1, max_in_group)
        d[(x, n)] = s
        return s


def find_index_of_number(number_to_test):
    global max_in_group
    a = []
    while number_to_test != 0:
        a.append(number_to_test % (max_in_group + 1))
        number_to_test //= max_in_group + 1
    print("number to test:", ",".join(f'{i:03d}' for i in a[::-1]))
    print("numbers should sum to:", sum(a))

    x = sum(a)  # all the solutions need this sum
    leftx = 0  # the sum of the numbers to the left of the group being processed
    s = 0
    for k in range(len(a) - 1, -1, -1):
        for l in range(a[k]):
            # e.g. when 6 groups and a[5] = 304, first take 303, count number in 5 groups which sum to x-303
            s += count_digitsums(x - leftx - l, k, max_in_group)
        leftx += a[k]
    print("number of smaller solutions:", s)
    print("index of this solution:", s + 1)
    return s + 1


d = {}
find_index_of_number(number_to_test)

输出:

number to test: 304,153,525,784,175,759
numbers should sum to: 2700
number of smaller solutions: 180232548167366
index of this solution: 180232548167367

【讨论】:

  • "数字总和为:2700" - 有没有办法改变这个数字?
  • 这只是输入的三项之和。否则,您无法为输入数字提供索引。如果将 x = sum(a) 替换为另一个值,该函数仍会正确计算小于输入的解的数量。
【解决方案2】:

编辑:这篇文章只讨论如何找到下一个解决方案,给定一个特定的解决方案。

OP 补充询问:

  • 给定一个索引 n 找到 nth 解决方案,而无需生成所有较早的解决方案。
  • 给定一个解决方案a,找出存在多少个更小的解决方案。

由于算法有效地找到下一个解决方案,您只需要填写您当前的解决方案。

这是一种将当前解决方案填充为大整数或字符串的方法:

start = 304153525784175759  # start = '304,153,525,784,175,759'
x = 2700
grouping = 3
max_in_group = 10**grouping - 1

if start is not None:
    if isinstance(start, str):
        a = [int(s) for s in start.split(',')[::-1]]
    else: # suppose start is a large integer
        a = []
        while start != 0:
            a.append(start % (max_in_group+1))
            start //= max_in_group+1
else: # no start value given, start with the smallest
    a = [x]

如果您将此添加到 other answer 的其余部分之前,您将获得输出:

304,153,525,784,175,759
304,153,525,784,176,758
304,153,525,784,177,757
304,153,525,784,178,756
304,153,525,784,179,755
304,153,525,784,180,754
304,153,525,784,181,753
304,153,525,784,182,752
304,153,525,784,183,751
304,153,525,784,184,750
304,153,525,784,185,749
304,153,525,784,186,748
...

【讨论】:

  • 这给出的是什么数字解?即这是从最低到最高的第 25000 个解决方案吗?
  • 不,要准确找出有多少早期解决方案,这是一个更棘手的问题。以及,给定索引,找出与它对应的解决方案。也许有一个递归公式?
  • 确实如此。对于较大的值,当前循环需要数月甚至数年才能完成
  • 谢谢。我主要是问“给定一个解决方案 a,找出存在多少个较小的解决方案”
  • 好的,谢谢。认为也许计算机算法是唯一的方法
猜你喜欢
  • 2020-04-06
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-12-04
  • 2018-09-17
  • 2021-12-15
  • 1970-01-01
相关资源
最近更新 更多