怎样快速求出一个数的所有最小因子的和 ?

languagec 2004-04-09 01:36:11
http://acm.zju.edu.cn/show_problem.php?pid=1133

是这个问题
我已经尽可能改进程序的速度了,能不调用函数的地方尽量不调用.
可是 还是太慢了.我实在是无能为力了.

#include <iostream.h>
long Sum(long num)
{
long sum=0;
while(num)
{
sum=sum+num%10;
num=num/10;
}
return sum;
}

long Prime(long num)
{
long s;
if(num%2==0) return 2;
for(s=3;s<num/2;s=s+2)
{
if(num%s==0) return s;
}
return num;
}

int main()
{
long need,sum=0,prime,t,Num;
cin>>need;
while(need!=0)
{
for(Num=need+1;;Num++)
{
if(Num!=Prime(Num))
{
for(prime=Num,sum=0,t=0;prime>1;prime=prime/t)
{
t=Prime(prime);
if(t<10)
sum=sum+t;
else
sum=sum+Sum(t);
}
if(sum==Sum(Num))
{
cout<<Num<<endl;
break;
}
}
}
cin>>need;
}
return 0;
}
...全文
1357 34 打赏 收藏 转发到动态 举报
写回复
用AI写文章
34 条回复
切换为时间正序
请发表友善的回复…
发表回复
shines77 2004-04-20
  • 打赏
  • 举报
回复
晕死, 还真的能回贴啊, 本来以为回不了的

我在ACM.ZJU这道题已经排排进前十了,无法突破0.01秒

在ACM.JLU我用时1.55s(总感觉是0.0155s)和第一名用时一样,他是PAS的, 内存比我少
shines77 2004-04-20
  • 打赏
  • 举报
回复
to liangbch(宝宝):

你的GetDigSum想法很好, 可实现起来效率并没有想象的好, 有些时候效率还低一些
liangbch 2004-04-15
  • 打赏
  • 举报
回复
to xmmx123(blueriver):你给出的判断素数的算法为米勒测试,这是速度最快的算法,但是它只是一个近似算法,它不能告诉你这个数是否100%为质数,这是一个冒险的算法,即使通过acm.
我给出一个算法,一定是最快的。这个算法包括2个表格,一个是质数表,存储了从2到到1万以内的所有质数,共1229个,占用空间 1229*sizeof(int)<5K, 一个1-10000以内的各个数数字的和,占用空间 1万* sizeof(char), 共10K.
写一个求10000以内的所有质数的程序(随你怎么写多成,速度无所谓),将其输出到一个 .c 文件,文件内容类似下面的样子:
const int prime_Tab[]=
{
2,3,5...
};
写一个求10000以内的所有数的各个数字和程序(随你怎么写多成,速度无所谓),将其输入到另一个文件,文件内容类似下面的样子:
const char DigSum_Tab[]=
{
0,1,2,3,4,5,6,7,8,9,1,2,3...
};
然后将这2个文件添加到你的project 中,使其成为源程序的一部分。

求一个各位数字的和的程序
int GetDigSum(int n)
{
if ( n<10000)
return DigSum_T[n];
int hi=n / 10000;
int lo=n % 10000;
return DigSum_T[hi]+DigSum_T[lo];
}

//找出 >=n 的smith 数。
int FindSmithNum(int n)
{
;先写道这里,有时间补上
}
shines77 2004-04-14
  • 打赏
  • 举报
回复
// SmithNum.cpp : Defines the entry point for the console application.
//

#include "stdafx.h"
#include <string.h>
#include <math.h>
#include <iostream.h>
#include "Elapsed.h"

#define USE_FASTER_PRIME

#define getisprime(i) ( ( prime_flag[(i)>>3] >> ((i)&0x7) ) & 0x1)
#define setnotprime(i) ( prime_flag[(i)>>3] |= (0x1 << ((i)&0x7)) )
#define setisprime(i) ( prime_flag[(i)>>3] &= (~(0x1 << ((i)&0x7))) )
#define getmaxszie(num) ( ((num) >> 3) + 1 )

#define _getisprime(i) ( ( prime_flag[(i)>>4] >> (((i) >> 1)&0x7) ) & 0x1)
#define _setnotprime(i) ( prime_flag[(i)>>4] |= (0x1 << (((i) >> 1)&0x7)) )
#define _setisprime(i) ( prime_flag[(i)>>4] &= (~(0x1 << (((i) >> 1)&0x7))) )
#define _getmaxszie(num) ( ((num) >> 4) + 1 )

#ifdef USE_FASTER_PRIME
#define CheckIsPrime _checkIsPrime
#else
#define CheckIsPrime getisprime
#endif

#define MAX_PRIME_NUM 100000000

unsigned char *prime_flag = NULL;

int checkInput(int num, int maxnum)
{
if(num < 2 || num > maxnum)
return -1;

return num;
}

__inline int _checkIsPrime(int num) // 0代表是质数, 1代表不是质数(即合数)
{
if(num == 2) // 偶数中只有2是质数
return 0;

if((num & 1)) // 非偶数
return _getisprime(num);
else // 偶数
return 1;
}

/* 求2-maxnum的质数序列 */
void _findprime(int maxnum)
{
int maxsize = _getmaxszie(maxnum);
// 分配prime_flag内存
prime_flag = (unsigned char*)malloc(sizeof(char)*maxsize);
if(prime_flag == NULL)
return;

// prime_flag初始化
memset(prime_flag, 0, sizeof(char)*maxsize);
//setnotprime(0); // 1不是质数, 值为0表示是质数,为1时表示是合数
//prime_flag[0] = 0x01;
_setnotprime(1); // 1不是质数

int del;
int count;
int dblcheck;
int halfmax;
int maxcheck = (int) ceil(sqrt(maxnum));
maxcheck = (maxcheck - 1)/2;
halfmax = (maxnum - 1)/2;
for(int check=1; check<=maxcheck; check++)
{
if(0 == getisprime(check)) // 找到序列中第一个不是合数的数(即是质数)
{
//del=check*3+1;
dblcheck=check*2+1;
del=dblcheck+check;
//count=maxnum/(check*2+1)/2;
count=halfmax/dblcheck;
for(int n=1; n<=count; n++)
//for(del=dblcheck+check; del<halfmax; del+=dblcheck)
{
if(0 == getisprime(del)) // 去掉这个质数的所有2以上的倍数
setnotprime(del);
del+=dblcheck;
}
}
}
}

int _countprime(int maxnum)
{
int nCount = 0;
for(int i=2; i<maxnum; i++)
if(_checkIsPrime(i) == 0)
nCount++;

return nCount;
}

/* 求2-maxnum的质数序列 */
void findprime(int maxnum)
{
int maxsize = getmaxszie(maxnum);
// 分配prime_flag内存
prime_flag = (unsigned char*)malloc(sizeof(char)*maxsize);
if(prime_flag == NULL)
return;

// prime_flag初始化
memset(prime_flag, 0x55, sizeof(char)*maxsize);
//setnotprime(0); // 0,1都不是质数, 值为0表示是质数,为1时表示是合数
//setnotprime(1);
//setisprime(2);
prime_flag[0] = 0x53;

int del;
int count;
int dblcheck;
int maxcheck = (int) ceil(sqrt(maxnum));
for(int check=3; check<maxcheck; check+=2)
{
if(0 == getisprime(check)) // 找到序列中第一个不是合数的数(即是质数)
{
del=check*3;
dblcheck=check*2;
count=maxnum/check;
for(int n=3; n<=count; n+=2)
{
if(0 == getisprime(del)) // 去掉这个质数的所有2以上的倍数
setnotprime(del);
del+=dblcheck;
}
}
}
}

int countprime(int maxnum)
{
int nCount = 0;
for(int i=2; i<maxnum; i++)
if(getisprime(i) == 0)
nCount++;

return nCount;
}

int Sum(int num)
{
int sum = 0;
while( num )
{
sum += num % 10;
num = num / 10;
}
return sum;
}

int Prime(int num)
{
if(0 == CheckIsPrime(num))
return num;

if((num % 2) == 0)
return 2;

int s;
for(s = 3; s < num/2; s += 2)
{
if((num % s) == 0) return s;
}
return num;
}

int main(int argc, char* argv[])
{
int nMaxPrime;
int nCount=0;
cout<<"Please input max range: ";
cin>>nMaxPrime;

int nSmithNum, nWantted;
int sum, prime, factor;
int sCount;

unsigned long nLong;
CElapsed Elapsed;

Elapsed.Begin();

#ifdef USE_FASTER_PRIME
_findprime(nMaxPrime);
nCount = _countprime(nMaxPrime);
#else
findprime(nMaxPrime);
nCount = countprime(nMaxPrime);
#endif

nLong = Elapsed.EndLong();
cout<<nCount<<endl;
cout<<nLong<<" us."<<endl;

do
{
cout<<"Input a number [2.."<<nMaxPrime<<"]: "<<endl;
cin>>nWantted;
} while(checkInput(nWantted, nMaxPrime) < 0);

while(nWantted != 0)
{
Elapsed.Begin();

sCount = 0;
for(nSmithNum = nWantted + 1; ; nSmithNum++)
{
if(1 == CheckIsPrime(nSmithNum))
{
for(prime = nSmithNum, sum = 0; prime > 1; prime = prime / factor)
{
factor = Prime(prime);
if(factor < 10)
sum += factor;
else
sum += Sum(factor);
}
if(sum == Sum(nSmithNum))
{
nLong = Elapsed.EndLong();
cout<<nSmithNum<<endl;
cout<<nLong<<" us."<<endl;
Elapsed.Begin();
sCount++;
if(sCount > 6)
break;
}
}
}

do
{
cout<<"Input a number [2.."<<nMaxPrime<<"]: "<<endl;
cin>>nWantted;
} while(checkInput(nWantted, nMaxPrime) < 0);
}

if(prime_flag)
{
free(prime_flag);
prime_flag = NULL;
}

return 0;
}
shines77 2004-04-14
  • 打赏
  • 举报
回复
输出10000000以后的6个Smith Number,效率比较:

我的代码:
Please input max range: 12000000 //初始化质数序列
788060
650077 us.
Input a number [2..12000000]:
10000000 //搜索10000000以后的6个

10000426 //第一个
2075 us. //搜索所花时间,单位us 1s=1000000us
10000642
1122 us.
10000678
169 us.
10000885
1044 us.
10001515
2959 us.
10001605
451 us.
10001749
672 us.

楼主的代码:
10000000 //搜索10000000以后的6个

10000426 //搜索出的第一个
4323469 us. //用时,单位us 1s=1000000us
10000642
2091287 us.
10000678
584352 us.
10000885
3205685 us.
10001515
7611546 us.
10001605
1374369 us.
10001749
1331229 us.

当然你也可以选择其他数字来测试,还跟楼主说一下,你测试运行时间的数是多少,单单从你给定的一个数能够证明程序的效率吗?怎样才能证明程序的效率呢,有一种方法是给定几个开始搜索的值比如n1, n2, n3, n4,n5等,分别从这些值开始搜索,求出平均使用时间

我觉得最科学的方法是,要求出从2到N(比如N=10000000)之内的Smith Number
这样程序的效率就凸现出来了,其实我的程序很多优化的余地
shines77 2004-04-14
  • 打赏
  • 举报
回复
我不是写了吗?代码和源码的下载地址都有啊,见上面
xstring 2004-04-14
  • 打赏
  • 举报
回复
和素数有关的问题很多的,先练练写一个快速求N以内所有素数的程序吧。

以后做这种题大有用处。
languagec 2004-04-14
  • 打赏
  • 举报
回复
long Prime(long num)
{
long s,t;
if(num%2==0) return 2;
t=sqrt(num);
for(s=3;s<t;s=s+2)
{
if(num%s==0) return s;
}
return num;
}

刚才改了一下一个子函数,竟然就过了,运行时间0.4s,不过还是人家的快.最快的是0.00s 就是运行时间忽略不计的那种.
languagec 2004-04-14
  • 打赏
  • 举报
回复
如果能很快分解出最小因子,得到答案就比较容易了.
xstring 2004-04-14
  • 打赏
  • 举报
回复
如果只是按楼主标题那样说的,还是比较容易的

acm上那道题就不easy了
xstring 2004-04-14
  • 打赏
  • 举报
回复
内存限制要求比较低一些,可以尽量利用内存。
xstring 2004-04-14
  • 打赏
  • 举报
回复
原来是acm的题。

没听说过最小困子这一说,只听说过质因子
shines77 2004-04-14
  • 打赏
  • 举报
回复
麻雀你可以去看看题目啊
http://acm.zju.edu.cn/show_problem.php?pid=1133

为什么要求最小因子,因为要把一个合数分解为N个质数的乘积。
xstring 2004-04-14
  • 打赏
  • 举报
回复
比如这个数的范围?

什么是最小因子?
xstring 2004-04-14
  • 打赏
  • 举报
回复
求一个数的所有最小因子之和

题目不太明确,你再明确一点,我可以给你写出来。
languagec 2004-04-14
  • 打赏
  • 举报
回复
1s 多 ,总之不符合要求
shines77 2004-04-14
  • 打赏
  • 举报
回复
to LeeMaRS(小菜虎,仍需努力)

下载这个就好了,里面有可执行文件exe,我加了时间的统计
http://www.77studio.net/files/SmithPrime.zip

hehe, 我还记得你, 那个桶式排序的帖子还记得吗?

我的程序忘了判断一个地方, 所以给出max range的时候尽量给个比你想搜索的范围稍大一点的数,因为要连续搜6个,忘了加个判断了,质数的标记位可能会越界.


LeeMaRS 2004-04-14
  • 打赏
  • 举报
回复
楼主的程序花了多少时间?
shines77 2004-04-14
  • 打赏
  • 举报
回复
SmithPrime.zip 是楼主的代码, 我改成联系输出6个Smith Number而已, 以便比较速度

我觉得这道题目应该给出N的几个参考值, 这样才能判定程序的效率, 或者求出所有从2-N的所有Smith Number, 不同的要求有不同的写法.

光是从4937774或者某个指定的值开始搜索, 不足以证明程序的效率
shines77 2004-04-14
  • 打赏
  • 举报
回复
源码可以到这里下载:
http://www.77studio.net/files/SmithNum.zip

我把你的也改了一下,下载地址:
http://www.77studio.net/files/SmithPrime.zip

当然使用这种方法,生产指定范围的质数的时候要花一定的时间,这肯定从时间上吃点亏的
但是在求多个Smith Number的时候那就凸现出效率了,所以上面的代码都是求出给定的N值后面的最近6个Smith Number, 所花费的时间精确到us (微秒,1s=1000ms, 1ms=1000us), 这个时候差距是很大的,

SmithNum.zip里使用了几种不同的求质数的方法(原理是一样的,有的优化了),可以看看

我不知道xstring(麻雀)的方法是怎么样的, 不过他的好快, 我不知道他的机器配置是多少,
我的是赛扬900, 384M内存, Win2000 Advanced Server+SP4
计算10000000以内的质数加统计个数要对要0.51x s(秒), 而且他的分配的内存很少, 有机会的话介绍介绍你的方法. 我的方法是参照网上一个公布的方法加入自己的理解写的, 很类似但基本都是基于我的理解, 速度相当.
加载更多回复(14)

33,010

社区成员

发帖
与我相关
我的任务
社区描述
数据结构与算法相关内容讨论专区
社区管理员
  • 数据结构与算法社区
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧