1、最多约数问题解题报告,叶梁 2006,一、题目内容,问题描述正整数x 的约数是能整除x 的正整数。正整数x 的约数个数记为div(x)。例如,1,2,5,10 都是正整数10 的约数,且div(10)=4。设a 和b 是2 个正整数,ab,找出a 和b之间约数个数最多的数x。 编程任务对于给定的2 个正整数ab,编程计算a 和b 之间约数个数最多的数。 数据输入输入数据由文件名为input.txt的文本文件提供。文件的第1 行有2 个正整数a和b。 结果输出程序运行结束时,若找到的a 和b 之间约数个数最多的数是x,将div(x)输出到文件output.txt中。输入文件示例 输出文件示例in
2、put.txt output.txt1 36 9,二、解题过程,A.常规枚举法int Divi (int m)int num=0;for (int j=1;jmax)max=dn;printf(“%d “,max); ,优化 int Divi (int m)if (m=1) return 1;int num=0, j;/for (j=2;j=m/j;j+)int k=sqrt(m);for (j=2;j=k;j+)if (m%j=0) num+=2;if (k*k=m)return (num+1);elsereturn(num+2); ,0 1 2 3 4 5 6 7 8 9 a b,56,大
3、大减少了枚举运算的次数,时间复杂性达不到要求,枚举的约数,被枚举的待求约数的数,Sqrt(56),二、解题过程,B.求AntiPrime法AntiPrime数:如果一个自然数n,满足所有小于n的自然数的约数个数都小于n的约数个数,则n是一个Antiprime数。譬如:1, 2, 4, 6, 12, 24,。性质:n=2k13k25k37k411K5 其中k1k2 k3 k4 k5 约数个数:sum=(k1+1)(k2+1)(k3+1)(k4+1)(k5+1),利用以上规律,用枚举质数的指数的方法,可以编程求出Antiprime数及其约数个数,运算速度极快,对应于本题,仅适用于a,b之间存在An
4、tiPrime数的情况(例如a,b间存在ap1,则最多约数是ap1的约数数);如果a,b间不存在AntiPrime数(例如下图中ap1不存在,只存在ap2),则还要用常规的枚举方法,二、解题过程,C.枚举质数法对常规枚举法的优化措施,达到题目要求,只用质数进行枚举(优化1) 利用约数通常是成对出现,搜索边界可以根据情况调整的规律(优化2) 对不会落在区间内的数中断枚举(优化3) 对不可能达到当前最大约数的情况,中断枚举(优化4),以上优化措施的落实见以下递归法中的标志。总而言之,尽可能地减少运算次数,重点关注多重循环和递归体内的程序块。,三、算法思想,Part a.求素数表(源程序请见.cpp
5、)Eratosthenes筛法 long int可表达的正整数是232-1,因此要用到的最到素数sqrt(232)=65536 定义数组int ArrInt65536,并将各单元的初值赋为1 将指针*p,定位在ArrInt2,若单元值为1,则使指针每次前进2个长度单位,将该地址内容置0,直至到达数组上界。再将指针移回ArrInt3,若单元值为1,指针每次前进3个长度单位,将该地址内容置0,直到全部循环完毕 剩下的未被置0(未被筛除)的单元所对应的在数组中的序号,即为素数 为使用方便,将素数写入数组Primes,三、算法思想,Part b.递归过程体void Iterative(int *pri
6、mes,int curPrime,int curNum,int curCount,int low,int up)int divLow,divUp,cur_num,calPrimeCount,curPri,count;int *p;/比较当前约数的个数,更新全局变量中的记录if (curNummaxCount) maxCount=curCount*2;if (curNum=lowB) ,优化1,优化2,三、算法思想,count=curCount;calPrimeCount=1; while (1) /枚举质因子个数calPrimeCount+;count+=curCount;divLow=div
7、Low/curPri;divUp=divUp/curPri;if (divLow=divUp) /质数不会落在搜索区间内break;cur_num=cur_num*curPri;Iterative(primes,i+1,cur_num,count,divLow+1,divUp);/搜索下一级int LeftPosCount=maxCountcalPrimeCount;if (curCountLeftPosCount)return; /约数个数无法超过当前最大值 ,优化3,优化4,优化2,优化2,三、算法思想,Part c.main函数void main() ifstream fin(“input.txt”);finlowBupB; /输入fin.close();int PrimesprimeCount;GenPrimes( ,四、时间空间复杂性,时间复杂性生成质数表的GenPrimes函数只计算一次,故其时间复杂度可忽略。递归部分的程序为了减少不必要的计算,存在许多短跳的行为,其时间复杂性难以计算,故以三种程序的运行实测结果进行比较。,空间复杂性程序的质数表Primes共有6542个数组长整形元素;递归部分最深可达6542层,形参+局部变量共有14个长整形变量;全局变量忽略不计:估算运算过程中数据占用内存量最高在384K左右,加上程序要400多K。,五、体会,