该程序遍历1到400的4个数字的每个组合,并查看可以从产品中生成多少个唯一数字。
我相信用于保存已经检查过的数字的unordered_set
变得过大,因此它会退出;任务经理告诉我它是1.5 GB。
有什么方法可以让这段代码运行?我想可能会拆分该组或以某种方式找到更有效的公式。
注意:根据评论,我想再说一遍,我没有存储所有250亿个数字。我只存储~100,000,000个号码。问题的RANGE
为400,但我正在寻找一个可以处理500甚至1000而没有内存问题的综合解决方案。
#include <iostream>
#include <unordered_set>
using namespace std;
const int RANGE = 400;
int main(){
unordered_set<long long> nums;
for(long long a=1; a<=RANGE; a++)
{
for(long long b=a; b<=RANGE; b++)
{
for(long long c=b; c<=RANGE; c++)
{
for(long long d=c; d<=RANGE; d++)
{
unordered_set<long long>::const_iterator got = nums.find(a*b*c*d);
if (got == nums.end())
{
nums.insert(a*b*c*d);
}
}
}
}
cout << a << endl;
}
cout << nums.size() << endl;
return 0;
}
答案 0 :(得分:5)
您需要使用64位编译器编译代码,以允许分配超过大约2GB的内存。你在运行它的机器上还需要至少4GB的RAM,或者最多需要几乎永远完成。
“bitset”,每个条目使用一位将占用大约3GB的内存。
使用现有的代码,它将在具有64位g ++编译器的Linux机器上使用大约4GB的内存,完成大约需要220秒,给出答案:
86102802
1152921504606846975
根据/ usr / bin / time -v:
Command being timed: "./a.out"
User time (seconds): 219.15
System time (seconds): 2.01
Percent of CPU this job got: 99%
Elapsed (wall clock) time (h:mm:ss or m:ss): 3:42.53
Average shared text size (kbytes): 0
Average unshared data size (kbytes): 0
Average stack size (kbytes): 0
Average total size (kbytes): 0
Maximum resident set size (kbytes): 4069336
Average resident set size (kbytes): 0
Major (requiring I/O) page faults: 0
Minor (reclaiming a frame) page faults: 679924
Voluntary context switches: 1
Involuntary context switches: 23250
Swaps: 0
File system inputs: 0
File system outputs: 0
Socket messages sent: 0
Socket messages received: 0
Signals delivered: 0
Page size (bytes): 4096
Exit status: 0
答案 1 :(得分:2)
您的解决方案的工作原理是对1到400之间的四个数字进行每个唯一的排列,将它们相乘,然后存储结果,然后计算它们。在最小,这将需要400 * 400 * 400 * 400bits~3GB,这显然比您的硬件/编译器/操作系统可以处理的更多。 (可能是编译器,很容易修复)
那么,如果我们尝试一步一步地解决该计划呢?我们能算一下这些数字中有多少套产品的产品在1000到2000之间吗?
for(a=1; a<400; ++a)
{
bmin = max(1000/a/400/400, a); //a*b*400*400 is at least 1000
bmax = min(2000/a, 400); //a*b*1*1 is at most 2000
for(b=bmin; b<=bmax; b++)
{
cmin = max(1000/a/b/400, b); //a*b*c*400 is at least 1000
cmax = min(2000/a/b, 400); //a*b*c*1 is at most 2000
for(c=cmin; c<=cmax; c++)
{
dmin = max(1000/a/b/c, c); //a*b*c*d is at least 1000
dmax = min(2000/a/b/c, 400); //a*b*c*d is at most 2000
for(d=dmin; d<=dmax; d++) //this will usually be zero, one, or two numbers
{
res = a*b*c*d;
if (res>=1000 && res<2000) //a rare few WILL be outside this range
YES
我们可以简单地计算0-1000之间可以访问的产品数量,然后是1000-2000,然后是2000-3000等,最多400 * 400 * 400 * 400。这是一个显着速度慢的算法,但由于它占用的内存非常少,所以希望增加的缓存一致性将弥补一些差异。
事实上,说到内存非常少,因为每批中的目标数字总是在1000的连续范围内,那么你可以使用bool nums[1000] = {}
而不是unordered_set
,这应该给出重要的性能提升。
我的完整代码在这里:http://coliru.stacked-crooked.com/a/bc1739e972cb40f0,我已经确认我的代码与您的代码具有相同的结果。在修复了几个错误之后,对于使用MSVC2013的小RANGE
,您的算法仍然远远超过我的算法。 (对于使用MSVC进行测试的其他人,请务必使用未附加的调试器进行测试,这会使原始代码的时序产生巨大差异)
origional( 4) found 25 in 0s
duck( 4) found 25 in 0s
origional( 6) found 75 in 0s
duck( 6) found 75 in 0s
origional( 9) found 225 in 0s
duck( 9) found 225 in 0s
origional( 13) found 770 in 0s
duck( 13) found 770 in 0s
origional( 17) found 1626 in 0.001s
duck( 17) found 1626 in 0s
origional( 25) found 5135 in 0.004s
duck( 25) found 5135 in 0.002s
origional( 35) found 14345 in 0.011s
duck( 35) found 14345 in 0.015s
origional( 50) found 49076 in 0.042s
duck( 50) found 49075 in 0.076s
origional( 71) found 168909 in 0.178s
duck( 71) found 168909 in 0.738s
origional( 100) found 520841 in 0.839s
duck( 100) found 520840 in 7.206s
origional( 141) found 1889918 in 5.072s
duck( 141) found 1889918 in 76.028s
当我研究这个问题时,最终发生的事情是我的算法需要大量的64位分区,即使在64位操作系统中也是如此。