我正在寻找一种方法来生成一系列数字,其倒数之和是一个整数?
例如 - 11(1/1 + 1/1 = 2是整数),122(1/1 + 1/2 + 1/2是整数),236(1/2 + 1 / 3 + 1/6是整数) 同样。
另外,我想避免重复相同的数字组合或排列。例如,如果打印122,我不想打印212和221。
我想知道如何解决这个问题
答案 0 :(得分:3)
让你开始的一些想法:
因此,以下方法可能有效:
这种自下而上的方法比检查所有可能的数字快得多。以下程序将在几分之一秒内打印所有14,137个有效数字(无序,即按生成顺序):
#include <stdlib.h>
#include <stdio.h>
#define NDIGIT 18
void rec(int set[], int n, int sum)
{
static int num[10] = {
0, 2520, 1260, 840, 630, 504, 420, 360, 315, 280
};
if (sum % 2520 == 0) {
for (int j = 0; j < NDIGIT - n + 1; j++) {
for (int i = 0; i < j; i++) putchar('1');
for (int i = 0; i < n; i++) putchar(set[i] + '0');
putchar('\n');
}
}
if (n < NDIGIT) {
int i0 = n ? set[n - 1] : 2;
for (int i = i0; i < 10; i++) {
set[n] = i;
rec(set, n + 1, sum + num[i]);
}
}
}
int main()
{
int set[NDIGIT];
rec(set, 0, 0);
return 0;
}
如果您需要排序输出,请将set
转换为长整数,可能是uint64_t
<stdint.h>
并将其存储在数组中,而不是立即打印它们。然后对数组进行排序并打印数字。
答案 1 :(得分:1)
首先,你有九个可能的数字(因为0
没有导致有效分数),其倒数有一个公约数2×2×2×3×3×5×7 = 2520:
1 -> 1/1 = 2520/2520
2 -> 1/2 = 1260/2520
3 -> 1/3 = 840/2520
4 -> 1/4 = 630/2520
5 -> 1/5 = 504/2520
6 -> 1/6 = 420/2520
7 -> 1/7 = 360/2520
8 -> 1/8 = 315/2520
9 -> 1/9 = 280/2520
因此,我们可以使用x/2520
来描述此类总和的确切值。当且仅当x
是2520
的倍数时,总和才是整数。我们可以使用modulo operator:if x % 2520 == 0
,分数x / 2520表示整数。
在实践中,我们根本不需要表示分数的值,我们只需要记住分子模2520,x % 2520
!
让我们看看以伪代码检查每个数字的倒数之和是否为整数的算法:
Constant Array per_digit_2520[10] = {
0, /* 0 -> 0/1 = 0/2520 */
2520, /* 1 -> 1/1 = 2520/2520 */
1260, /* 2 -> 1/2 = 1260/2520 */
840, /* 3 -> 1/3 = 840/2520 */
630, /* 4 -> 1/4 = 630/2520 */
504, /* 5 -> 1/5 = 504/2520 */
420, /* 6 -> 1/6 = 420/2520 */
360, /* 7 -> 1/7 = 360/2520 */
315, /* 8 -> 1/8 = 315/2520 */
280, /* 9 -> 1/9 = 280/2520 */
}
Function corresponds_to_whole_fraction(digits):
Let remain = 0
For each digit d in digits:
remain = (remain + per_digit_2520[d]) % 2520
End For
If remain == 0:
Return "Yes, the digits represent a whole fraction"
Else:
Return "No, the digits do not represent a whole fraction"
Fi
End Function
在上面的循环中,您还可以检查数字d
是否为零,如果是,则拒绝该组数字。
通过编写上述内容,我们可以立即注意到,因为总和中分数的顺序不会改变总和,所以数字的所有组合都会产生完全相同的倒数位数之和。
换句话说,如果236产生一个总和(确实如此,因为1/2 + 1/3 + 1/6 =(1260 + 840 + 420)/ 2520 = 2520/2520 = 1),那么也是326 ,362,623和632产生相同的总和。每个数字都是数字集的唯一permutation。为了进一步探索排列,我们需要查看combinatorics。
幸运的是,corresponds_to_whole_fraction()
很简单,通过顺序生成普通数字或使用随机数生成器生成所需数字是合理的(对于最多18位的数字,我建议{{3}自2 64 &gt; 10 18 )。
让我们考虑顺序情况:
#include <stdlib.h>
#include <inttypes.h>
#include <stdio.h>
const unsigned int num_2520[10] = {
0, 2520, 1260, 840, 630, 504, 420, 360, 315, 280
};
int is_acceptable(uint64_t value)
{
unsigned int remain = 0;
if (!value)
return 0;
while (value > 0) {
const unsigned int digit = value % 10;
if (!digit)
return 0;
value /= 10;
remain = (remain + num_2520[digit]) % 2520;
}
return (remain == 0);
}
uint64_t next_number(uint64_t previous)
{
while (++previous)
if (is_acceptable(previous))
return previous;
return 0;
}
int main(void)
{
uint64_t value = 0;
while (1) {
value = next_number(value);
if (!value)
break;
printf("%" PRIu64 "\n", value);
}
/* Never reached */
return EXIT_SUCCESS;
}
上述程序打印1
和2 64 -1 = 18446744073709551615
之间的所有数字,包括它们,其倒数的总和是一个整数。它们太多了,任何人都不能等待足够长的时间来打印它们。
密度约为10%左右的0.05%-0.1%,即平均而言,每千分之一(或千分之二千)数是可接受的(尽管有很多变化)。所以,如果你从一个随机数开始,你可能希望检查从该随机数开始的连续数字,而不是每次都尝试所有新的随机数(因为随机数字生成器起初不是很快)。
如果您想将上述内容限制为18位数,请从uint64_t value = UINT64_C(99999999999999999);
(17个9)开始,并将if (!value)
替换为if (value > UINT64_C(999999999999999999))
(18个9)。