豪杰公司的一道初试问卷题:
求出10的10次方以内的素数,并针对提高效率简要介绍所使用的技巧.
-请记录程序完成计算所需的时间(我们期望它小于10小时),以及计算机的配置.(缺少这个数据的回答不会被评分.)
-不需要输出或者保存结果,请在确定一个数是素数的地方用注释标出.
各位XDJM看看有什么高招。
我抛砖引玉先:
首先可以确定一个条件就是,不能被2整除的数,绝对也不可能被2的倍数整除,所以我从3开始验证,步长为2,前提是验证是否可以被2整除。
我的程序运行了接近30小时,才完成。
求出10的10次方以内的素数,并针对提高效率简要介绍所使用的技巧.
-请记录程序完成计算所需的时间(我们期望它小于10小时),以及计算机的配置.(缺少这个数据的回答不会被评分.)
-不需要输出或者保存结果,请在确定一个数是素数的地方用注释标出.
各位XDJM看看有什么高招。
我抛砖引玉先:
首先可以确定一个条件就是,不能被2整除的数,绝对也不可能被2的倍数整除,所以我从3开始验证,步长为2,前提是验证是否可以被2整除。
我的程序运行了接近30小时,才完成。
解决方案 »
- 如何调用createprocess 运行一个exe界面嵌入到当前的MFC界面
- 求助:MFC中List Control中怎样添加数据
- VS2010 MFC 基于SQL SERVER 2008数据库编程
- 完成端口 WSASend疑问 送分
- 如何把CFontDialog添加到一个属性表里!!!!!或类似的办法,高手帮忙
- 難道CSDN就沒有高手嗎!!!我把Source Code都拿出來了,竟無人能Debug!!!
- 问,在vc++中 .DEF 文件在什么地方
- 如何获得http://www8.pconline.com.cn/download/download.phtml?id=105061的文件名
- SVN残留文件删不了
- 要加MessageBox("*");对话框程序才能正常运行,请助~
- Edit 等几个小问题
- 如何判断一个各个文件的类型
CUIntArray arPrime;
arPrime.Add(3);
int num ;
for(int i = 5 ; i < N ; i+=2)
{
num = arPrime.GetSize();
for(int j = 0 ; j < num ; j++)
if(0 == i % arPrime[j] )
break;
if(j == num)
arPrime.Add(i);
}
int *arPrime = new int[100000];
arPrime[0] = 2;
arPrime[1] = 3 ;
int num = 2 ;
for(int i = 5 ; i < N ; i+=2)
{
for(int j = 1 ; j < num ; j++)
if(0 == i % arPrime[j] )
break;
if(j == num)
arPrime[num++] = i;
}
delete [] arPrime; AfxMessageBox("end!");
10的6次用了二分钟
慢
大侠你的算法的确有点慢了,因为除掉2以外的素数只有两类:一种是除以4余数是1的,如5,13,17等;另外一种是除以4余数是3的,如3,7,11,19等等。
另:嵌套循环的终止条件可以为当前数的平方根,可以减少很大的循环次数,但是即便如此我仍然对我的程序运行速度不满意,虽然每分钟可以运行到4*1000000以上,呜呼呀。
还是希望各位不吝赐教,鞠躬......
DWORD FastCount()
{
INT64 nMax = 1000000l;
CMap<INT64, const INT64&, BOOL, BOOL&> mapResult; DWORD nCount = 2;//1,2
INT64 iStep = 2;
INT64 i = iStep;
while(iStep <= nMax)
{
i += iStep;
if(i <= nMax)
{
mapResult[i] = TRUE;
}
else
{
while(++iStep <= nMax && mapResult[iStep])
mapResult.RemoveKey(iStep);
if(iStep <= nMax)
{
i = iStep;
++nCount;
}
TRACE1("now result %ld\n", iStep);
}
} return nCount;
}使用的是筛选法,10的6次用了一分半钟,机器是K7-600,256M内存,运行期间使用大概4M内存。
不知道你有没有看到ross33123大侠说的,嘿嘿,我非常想看看他的代码,哎可惜没有给我。我觉得他说的方法还不错,正在考虑怎么去做涅。
#include <stdlib.h>
#include <windows.h>#define NND 10000000
bool b[NND];int main(int argc, char* argv[])
{
DWORD start = GetTickCount();
b[0] = b[1] = 1;
int i = 2;
while( i <= NND / 2 )
{
int j = i * 2;
while( j < NND )
{
b[j] = true;
j += i;
}
j = i + 1;
while( b[j] )
j ++;
i = j;
}
printf("Time elapsed is %d ms.", int(GetTickCount() - start));
return 0;
}
先谢谢,然后读代码。
while( b[j] )
j ++;
改为
while( j <= NND / 2 && b[j] )
j ++;
否则可能溢出,虽然实际运行没有发生问题 :-)
大侠请问方便给其他的联系方式吗?希望能跟您学习一下,嘿嘿,:P
#include <windows.h>#define NND 10000000
bool b[NND]; // true 表示筛去int main(int argc, char* argv[])
{
DWORD start = GetTickCount();
b[0] = b[1] = true;
int i = 2;
while( i <= NND / 2 )
{
for( int j = i * 2; j < NND; j += i )
b[j] = true;
i ++;
while( i <= NND / 2 && b[i] )
i ++;
}
printf("Time elapsed is %d ms.", int(GetTickCount() - start));
return 0;
}
我觉得讨论算法的效率有一个前提就是牺牲的空间不能太大,象 ross33123() 的代码中有
#define NND 10000000
bool b[NND]; // true 表示筛去
这样的做法我觉得降低了算法的含金量。
个人看法,不必当真。
我同意 完全抵制日货 这个观点,因为我们被日本这个民族所侮辱着,从抗战结束一直到现在他们一直像个婊子一样对美国献媚,而对任何他们伤害过的国家都是高高在上,自认为自己是高等民族而我们是卑劣民族。
我有的时候就在想,为什么我们的国家没有像韩国那样抵制日本呢?为什么不管日本怎么伤害我们,我们总选择沉默呢?
我觉得是我们应该做出点什么的时候了
这种分配内存的方法是无法分配出10的10次方大小的内存来的!!!
所以在我的程序里用的是map分配内存,虽然算法跟你的程序本质是相同,但效率低了,这也是无可奈何之举。
算法大家都会,真正要解决的问题是10次方!
如果不能算到10 次方,你的简化版本在这里并没有解决真正的问题啊。
NO.2 999999929
NO.3 999999893
NO.4 999999883
NO.5 999999797
NO.6 999999761
NO.7 999999757
NO.8 999999751
NO.9 999999739
NO.10 999999733
NO.11 999999677
NO.12 999999667
NO.13 999999613
NO.14 999999607
NO.15 999999599
NO.16 999999587
NO.17 999999541
NO.18 999999527
NO.19 999999503
NO.20 999999491
NO.21 999999487
NO.22 999999433
NO.23 999999391
NO.24 999999353
NO.25 999999337
NO.26 999999323
NO.27 999999229
NO.28 999999223
NO.29 999999197
NO.30 999999193
NO.31 999999191
NO.32 999999181
NO.33 999999163
NO.34 999999151
NO.35 999999137
NO.36 999999131
NO.37 999999113
NO.38 999999107
NO.39 999999103
NO.40 999999067
NO.41 999999059
NO.42 999999043
NO.43 999999029
NO.44 999999017
NO.45 999999001
NO.46 999998981
NO.47 999998971
NO.48 999998959
NO.49 999998957
TO:ross33123() 和 Cline(营营)
两位大侠能不能讲讲二位分块筛分的具体做法啊,最好给兄弟们共享一点代码,偶比较愚钝。哎呀,不要用砖头砸我。
哎,看样子自己真的是笨笨哦,悲哀死。
last 10 prime numbers:
999999937
999999929
999999893
999999883
999999797
999999761
999999757
999999751
999999739
999999733
#include <windows.h>#define NND 1000000000
#define SRD 31623
//bool b[NND];
BYTE c[NND / 8 + 1];int main(int argc, char* argv[])
{
DWORD start = GetTickCount();
//b[0] = b[1] = true;
c[0] |= 1; c[0] |= 2;
int i = 2;
while( i <= SRD )
{
for( int j = i * i; j < NND; j += i )
{
if( j%8 == 0 )
c[j/8] |= 1;
else
c[j/8] |= (2 << (j%8-1));
}
i ++;
while( i <= SRD && ( c[i/8] & ( i%8 ? (2 << (i%8-1)) : 1 ) ) )
i ++;
}
printf("Time elapsed is %d ms.\n", int(GetTickCount() - start));
printf("last 10 prime numbers:\n");
int j = NND - 1;
for( int k = 0; k < 10; k ++ )
{
while( c[j/8] & (j%8 ? (2 << (j%8-1)) : 1) )
j --;
printf("%d\n", j);
j --;
} return 0;
}
用的是Sieve地实现方法,感觉效果没有明显的改善。10的10次方没有计算,太麻烦了,要求的空间太大了,要分段计算。不知道有没有其他好的办法。
#include "math.h"
//////////////////////////////////////////////////////////////////////////
// Sieve find primes
INT Sieve(UINT nMax)
{
int nCount = 0;
PBYTE pBuffer = (PBYTE)GlobalAlloc(GMEM_ZEROINIT, sizeof(BYTE)*(nMax/8+1));
UINT nLimit = 100000/*sqrt(nMax)*/;
UINT i = 2;
DWORD dwStart = GetTickCount(); //record start timer
for (i = 2; i <= nLimit; ++i)
{
if (!(pBuffer[i/8] & (1<<(i%8))))
{
for (UINT k=i + i; k <= nMax; k += i)
{
pBuffer[k/8] |= 1<<(k%8);
}
}
}
DWORD dwTimer = GetTickCount() - dwStart;
for (UINT j=2; j<=nMax; ++j)
{
if (!(pBuffer[j/8] & (1<<(j%8))))
{
++nCount;
}
}
printf("%d\n", dwTimer);
for( int k = 0; k < 10; ++k )
{
while( pBuffer[j/8] & (1<<(j%8)))
{
j --;
} printf("%d\n", j);
j --;
}
GlobalFree(pBuffer);
return nCount;
}INT main()
{
Sieve(UPPER_RANGE); return 0;
}