最多约数问题答案解析与勘误
来源:互联网 发布:matlab矩阵点乘 编辑:程序博客网 时间:2024/05/22 00:18
问题描述:
正整数x的约数是能整除x的正整数。正整数x 的约数个数记为div(x)。例如,1,2,5,10 都是正整数10 的约数,且div(10)=4。设a 和b 是2 个正整数,a≤b,找出a和b之间约数个数最多的数x。
编程任务:
对于给定的2个正整数a≤b,编程计算a 和 b 之间约数个数最多的数。
数据输入:
输入数据由文件名为input.txt的文本文件提供。文件的第1 行有2 个正整数 a和 b。
结果输出:
程序运行结束时,找到a 和b之间约数个数最多的那个数及最多约数个数。
测试数据:【只给出最多约数个数, time limit: 1s】
问题分析
下面的解析摘自网上一篇博客(来源http://blog.csdn.net/sarah_jieyu/article/details/6512030),标红部分是我自己添加上去的。
根据以上分析给出以下代码
#include<iostream>
using namespace std;
void primes(); //用筛选法产生质数存于prim数组中
void search(long from, long total, long num, long low, long up);
const long MAXP = 100000;
long prim[MAXP];
//long max, numb ,PCOUNT; //max存放最多约数个数,numb存放约数个数最多的数
long max_num;
long numb,PCOUNT;
int main()
{
primes();
long low, up;
cin >> low >> up;
if ((low == 1) && (up == 1))
{
max_num = 1;
numb = 1;
}
else
{
max_num = 2;
numb = low;
search(1, 1, 1, low, up);
}
cout << max_num << endl << numb << endl;
return 0;
}
//求小于100000的素数表
void primes()
{
bool get[MAXP+1];
long i;
for (i = 2; i <= MAXP; i++)
get[i] = true;
for (i = 2; i <= MAXP; i++)
if (get[i])
{
long j = i + i;
while (j <= MAXP)
{
get[j] = false;
j += i;
}
}
long ii, j;
for (ii = 2, j = 0; ii <= MAXP; ii++)
if (get[ii]) prim[++j] = ii;
PCOUNT = j;
}
// 区间[low,up]上,tot为当前约数最多个数,num为约数个数最多的数,
//from表示现在是第几个质数。
void search(long from, long total, long num, long low, long up)
{
/*cout<<"from is "<<from<<endl;
cout<<"total is "<<total<<endl;
cout<<"num is "<<num<<endl;
cout<<"low is "<<low<<endl;
cout<<"up is "<<up<<endl;
cout<<"numb is "<<numb<<endl<<endl;*/
if (num >= 1){
//下面加注释的是网上广泛流传的代码,其实是错的,因为这种条件判断不能保证最后得到的因数个数最多的数大于区间的下边界
/*
if ( (tot > max) || ((tot == max) && (num < numb)) )
{
max = tot;
numb = num;
}*/
//这是我修改后的代码
if ( (total >=max_num&&num>=numb) )
{
//cout<<"total"<<endl;
max_num = total;
numb = num;
}
}
/**
此处代码较为简练,但包含的内容很多,较难理解.
因为所给区间[low,up]内有可能包含一个数a,a的某个因子大于100000,超出了素数表的搜索范围
有可能搜索不到a,怎么解决这个问题?可以看出来,如果a含有大于100000的因子,则a的因数个数为当前搜索到的因数个数乘以2
如果,一个区间内包含了一个和a含有除了大于100000的因子的数以外的其他因子的数b,那么b的因数个数一定多于a.因此对于
含有a的区间,我们只考虑[a,a]这种可能,其他的区间情况,a不可能是含有因数最多的数。
此处给出的判断条件是low==up,low>num。就包含了[a,a]这种情况,当然此处会有多余的情况,如low=up=b,b可以分解为若干个较小的因子的乘积
但并不影响最终的结果。
*/
if ((low == up) && (low > num))
search(from, total*2, num*low, 1, 1);
/*此处就是深度搜索的代码 ,有一个地方需要补充说明一下,在一条搜索路径上,区间边界不断除以一个素数,
会越来越小,因为每次使用的都是除法取整,会有误差。但这里可以证明,累积误差不会导致的除法结果的整数部分不同。
即:a/(x1*x2*..xn)=a/x1*1/x2*1/x3*..*1/xn,证明:设a=c(x1*x2*..*xn)+r(r为余数),则a/x1*1/x2*..1/xn=c+r/x1*1/x2*..*1/xn,整数部分仍然为c
*/
for (long i = from; i <=PCOUNT; i++)
{
if (prim[i] > up) return;
else
{
long j = prim[i], x = low - 1, p=low,y = up, n = num, t = total, m = 1;
while (true)
{
m++;
t += total;
x /= j;
y /= j;
p/=j;
/*
此处x==y的判断剪枝根据是如果(min-1)/number=max/number,则[min,max]内不包含可以被number整除的数
*/
if (x == y)
break;
n *= j;
/*
勘误,此处网上流传的代码为search(i+1, t, n, x+1, y);,这个是不对的,因为(low-1)/j+1和low/j整数部分会产生误差,
例,low=9,j=2,(low-1)/j+1=5,而low/j=4,所以此处进行了更正。下面一些测试数据可以测出错误代码的结果是不正确的
[9999999,10000000],[99999999,100000000],[999999999,1000000000]
*/
//search(i+1, t, n, x+1, y);
search(i+1, t, n, p, y);
}
/*
此处也是剪枝处理
*/
m = 1 << m;
if (total < max_num / m) return;
}//end else
}//end for
}
- 最多约数问题答案解析与勘误
- 最多约数问题
- 最多约数问题
- 最多约数问题
- 最多约数问题
- 【最多约数问题】
- 问题八十六:最多约数
- 最多约数问题
- 最多约数问题
- 【最多约数问题】
- 最多约数问题
- 最多约数问题
- NOJ1203 最多约数问题
- 最多约数问题
- 最多约数问题
- 最多约数问题
- 最多约数问题
- 最多约数问题
- mysql_connect() 不支持 请检查 PHP 配置的错误
- linux中用到的命令
- 我在互联网创业失败的启思录(五) –--敢梦想,敢追寻
- JVM调优总结(四)--新一代垃圾回收算法G1
- Linux--线程编程
- 最多约数问题答案解析与勘误
- 把IList和泛型数组转换为DataTable
- 防止ios6下中文输入时,锁屏lock screen导致crash
- 【转载】C代码阅读工具(2)---ctags
- JVM调优总结(五)--调优方法及反思
- over partition by与group by 的区别
- Nginx负载均衡和LVS负载均衡的比较分析
- Debian 6.0.6 系统安装第一步: 更新/etc/apt/sources.list
- Android模拟器DPAD not enabled in avd