C++代码如下:
#include <iostream>
#include <vector>
#include <stdint.h>
using namespace std;
int main(void)
{
vector<int> rg;
for (int i = 2; i < 32; ++i)
{
rg.push_back(i);
}
int hit = 0, hit1 = -1, hit2 = -1;
for (__int64 i = 1; i < INT64_MAX; ++i)
{
for (unsigned int j = 0; (hit <= 2) && (j < rg.size()); ++j)
{
if (i % rg[j] != 0)
{
hit++;
if (hit == 1)
{
hit1 = j;
}// if
else if (hit == 2)
{
hit2 = j;
}//else if
else
{
break;
}// else
}//end if
}// end for
// ! <span style="color:#ff0000;">注意这里if语句的位置</span>
if (hit == 2 && hit1 + 1 == hit2)
{
cout << i << endl;
}//end if
}// end for
return 0;
}
提出三个问题:
问题1:
这个程序要找的是符合什么条件的数?
问题2:这样的数存在么?符合这一条件的最小的数是什么?
问题3:
在电脑上运行这一程序,你估计要多长时间才能输出第一个结果?时间精确到分钟(电脑配置:单核CPU2.0GHz,内存和硬盘资源充足)
---------------------------分割线 个人一些想法----------------------------
针对问题1:
注意一下if语句的位置,刚开始看题时以为if语句在内层for循环里面,结果就理解错了,错了,了~
仔细分析一下,程序的目的是找出一个数,这个数满足以下性质:
不能被rg数组内的某两个连续数整除,但是能被数组内的其他数整除。
[假设rg数组的元素个数为N 这里 N = 30]
即等价为:<=>
找一个NUM 满足 NUM % rg[i] == 0 && NUM % rg[i + 1] == 0 && NUM % rg[j] != 0 【0≤i<N-1 0≤j<N】
针对问题2:
碰到这种取余的运算,条件反射想到 最小公倍数 最大公约数等等。
恩 但这道题没有那么容易。
首先NUM仅且只能不被两个rg数组内的数整除。 (rg数组内数的范围是2~31)
假设不能被整除的第一个数为rg[i] 第二个即为rg[i + 1]
很显然 15是一个分界线 比如 30 = 2 * 15 那么rg[i] ≤ 15 很明显不行 至少不能被三个数整除。。(想想看 是不是这样)
接下来考虑的就是数组内元素之间的因子转换了 【记得找 大于15的数】
16 = 2 * 8
18 = 2 * 9
20 = 4 * 5
21 = 3 * 7
22 = 2 * 11
24 = 3 * 8
...
30 = 2 * 15
分析一下:
上面列出的一些因子乘式中 两个因子看似没有很大关系 似乎找不到要找的数。
如果NUM能整除两个因子 那么必然NUM肯定能整除它们的乘积(再次想想看 是不是这样)
因此 这样好像就是找不到了。。找不到。。找不到?!
-------------到底错在哪----------------
好吧 其实我们没有考虑两个因子之间的关系 什么关系呢~
----------万一两个因子之间是可以整除的!!!---------
上面满足这一条件的是 16 = 2 * 8 其中因子2可以整除因子8。
因此 rg[i] = 16 rg[i + 1] = 17
问题转化为 : 找不能被16和17整除 但能被其他数整数整除的数。
接下来找最小的那个。。
任何一个非素数都可以写成 2^k1 * 3^k2 * 5^k3的形式。(k1 k2 k3 ≥ 0)
要想整除16和17外所有的数 这个数至少满足:
整除8
整除27
整除25
整除其余的素数(除 2 3 5 17外)
即:
2^3 * 3^3 * 5^2 * 7 * 11 * 13 * 19 * 23 * 29 * 31 ===>2123581660200
针对问题3:
参考网络上答案的解释~感谢
再次感叹
数学之美~
编程之美~