从 1 到 100 这 100 个数字中任意选取 10 个数,求这 10 个数字的倒数之和为 1 的所有可能结果。
扩展: 从 1 到 n 这 n 个数字中随机选取 m 个数,求这 m 个数字的倒数之和为 1 的所有可能结果。

从 1 到 100 这 100 个数字中任意选取 10 个数,求这 10 个数字的倒数之和为 1 的所有可能结果。
扩展: 从 1 到 n 这 n 个数字中随机选取 m 个数,求这 m 个数字的倒数之和为 1 的所有可能结果。
1 vituralfuture Feb 24, 2024 via Android 枚举法,注意一下为了避免浮点数误差,不要直接取倒数,把先分母弄到等号另外一边,消除分母 |
2 Rang666 Feb 24, 2024 via iPhone 递归就行,第一个是 a ,就 1-100 选 9 个,求倒数是 1-1/a |
3 forgottencoast OP |
4 v2er4241 Feb 24, 2024 标题应改为“算法求解” |
5 v2er4241 Feb 24, 2024 然后建议问问 GPT |
6 phrack Feb 24, 2024 递归加减枝,标准操作 |
7 neteroster Feb 24, 2024 每次选择上界稍微剪一下(选 m 个倒数和为 k 的话最小那个一定要小于 m/k 了)就跑的出来了,总共 69014 组,不知道有没漏。应该还可以再优化。 |
8 forgottencoast OP @klo424 它不会,或者说给出的答案很差。 |
9 forgottencoast OP |
10 neteroster Feb 25, 2024 @forgottencoast 我最近在学 Racket ,所以用这个语言写的。这语言编译后基本操作大概比 C / C++ 慢一个数量级。 我后来还加了一个小优化,最后三个数直接查表(提前算好)。总时间在我电脑上大概 9 秒,代码和具体计时详见: https://gist.github.com/neteroster/9f59b6a868ef26fc7a43ce6a3eaac4bd |
11 forgottencoast OP |
12 v24radiant Feb 26, 2024 根据上面的代码改成 python, 优化一下剪枝, 总运行时间如下: 3.18 s ± 211 ms per loop (mean ± std. dev. of 7 runs, 1 loop each) python 代码如下: ```python %%timeit import itertools min_sum = [0 for _ in range(10)] min_sum[0] = 1 / 100 for i in range(1, 10): min_sum[i] = min_sum[i - 1] + 1 / (100 - i) with open('resf.txt', 'w') as res_port: res_port.write("make table: \n") sum_table = {} for i in range(1, 101): for j in range(i + 1, 101): for k in range(j + 1, 101): key = 1 / i + 1 / j + 1 / k if key not in sum_table: sum_table[key] = [] sum_table[key].append((k, j, i)) def backtrack(path, start, target, n): if target < min_sum[n - 1]: return if n == 3: if target in sum_table: for c in sum_table[target]: if c[2] >= start: res_port.write(str(list(path) + list(c)) + '\n') else: kmax = int(n / target) end = min(100, kmax) + 1 start = max(start, int(1 / target)) for i in range(start, end): if 1 / i < target: backtrack(path + (i, ), i + 1, target - 1 / i, n - 1) res_port.write("backtrack: \n") backtrack((), 1, 1, 10) ``` |