杭电ACM——CallingExtraterrestrialIntelligenceAgain(搜索)

由于只学了单纯用循坏找素数的方法,且此方法复杂度很高,不适合大数据,题中要求4<=m<=100000,如果找出100000内所有质数,肯定会超时,因此需要进行“剪枝”。
一、分析,所要求的质数p,q须满足pq<=m, a/b<=p/q<=1, 其中,1<=a<=b<=1000,即Min(a/b)=1/1000。当p<=10时,欲满足p/q>=1/1000,此时q不应超过10000,否则p/q将小于1/1000;当p>=10时,因pq不可大于100000,所以q不应超过10000。因此,p<=10000,于是,我们只需找出10000以内的质数就行,大大减少了计算量。
二、上面是通过将计算范围缩小来减少计算量的。将10000以内的质数存入一个数组prime后,下面还需进行进一步的“剪枝”,这一部分的“剪枝”,结合代码解释比较容易,故插入一下代码中。

#include<stdio.h>
#include<string.h>
int prime[3000],n=1;         //10000以内的素数事实上不会超过2000,n用以表示prime数组的元素序号,在此定义为全局变量会比较方便
void prime_search()               
{
int i,j;
for(i=3;i<=10000;i++)
{
for(j=2;j<=sqrt(i);j++)
    if(i%j==0) break;
if(j>sqrt(i))
{
prime[n]=i;
n++;
}
}
}
int main()
{
int m,a,b,p,q,max;   //p,q用于记录p'*q'<=m最大的那一对,max用以辨别
double s1,s2;
prime[0]=2;
prime_search();
while(scanf("%d%d%d",&m,&a,&b)&&m&&a&&b)
{
max=-1;   //循坏开头初始化为-1,因为p*q不可能为负数
p=0;q=0; //初始化数据
s2=(double)a/(double)b;  //注意格式,切不可写成s2=(double)a/b;
int i,j;
for(i=n-1;i>=0;i--)    //建议从大到小搜索,prime[i]最终赋予p
    if(prime[i]>m) continue;  //“剪枝”:prime[i]显然要小于m,不满足时跳过当前循坏
    else
    for(j=i;j<=n-1;j++)
    {       //    printf("%d %d b\n",prime[i],prime[j]);  (这是在dig bug)
    if(prime[j]>m) break;  //“剪枝”:同上
    s1=(double)prime[i]/(double)prime[j];   //    printf("%.2lf %.2lfc ",s1,s2);(同样是在dig bug)
    if(prime[i]*prime[j]<=m&&s1>=s2&&prime[i]<=prime[j])
    {
    if(prime[i]*prime[j]>max)
    {
    max=prime[i]*prime[j];
    p=prime[i];q=prime[j];          // printf("%d %d %d %d a",p,q,i,j);
}
}
}
printf("%d %d\n",p,q);
}
return 0;
 } 

小结:当所采取的搜索复杂度太高时,有两种方法解决:一是采用更高效的算法;二是进行“剪枝”。“剪枝”很重要,但“剪枝”的同时也应考虑仔细,如若“剪枝”错误,将可能导致结果错误。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值