题解 UVA543 【Goldbach's Conjecture】

素数筛法,就是在原暴力求解素数代码的基础上,将算法变成线性的。 那么,怎么操作呢??!!

代码:

#include <bits/stdc++.h>
using namespace std;
int n,w,ans[1000010],tot,s;
bool vis[100000010];
int main(){
    cin>>n>>w;
    for(int i=2;i<=n;i++){   
        if(vis[i]==false) 
           ans[++tot]=i;
        for(int j=1;j<=tot&&i*ans[j]<=n; j++) {
            vis[i*ans[j]]=true;
            if(i%ans[j]==0) 
               break;
        }
    }
    for(int i=1;i<=w;i++){
        cin>>s;
        int left=1,right=tot,mid;
        while(left<=right){ 
            mid=(left+right)/2;
            if(s==ans[mid]){ 
               cout<<"Yes"<<endl; 
               break; 
            }
            else if(s<ans[mid]) 
                right=mid-1;
            else 
                left=mid+1;
        }
        if(s!=ans[mid]) 
           cout<<"No"<<endl;
    }
    return 0;
}

这里显然就运用到了筛素数的进一步优化,就是将每一个质数以及它的倍数筛掉,比如说12就可以等于3*4,那么,12就显然不是质数,这样,将所有质数保存在一个数组里,最后只要查找一下就可以了,这真是太棒了!!! 那么,原题的进一步线性优化就是这样的:

#include <iostream>
#include <cstdio>
using namespace std;
const int maxn=1000+10,maxm=1000000+10;
int a[maxn],p[maxm],m;
void doing(){
    for(int i=2;i<=750;i++)
        if(!p[i]){
            a[++m]=i;
            for(int j=i*i;j<=maxm;j+=i)
                p[j]=1;
        }
}
int main(){
    int x;
    doing();
    while(1){
        cin>>x;
        if(x==0)
           return 0;
        for(int i=2;i<=x/2;i++)
            if(p[x-i]==0&&p[i]==0){
               cout<<x<<" = "<<i<<" + "<<x-i<<endl;
               break;
            }
    }
    return 0;
}

但是,这个程序还不是最优的,因为12既可以等于34也可以等于26,这样岂不是连续算了多遍??!!

那么,我们可以在原代码上进行进一步优化,如果能将重复算的部分删掉就好了,其实,是可以这样的,代码如下:

#include<bits/stdc++.h> 
using namespace std;
const int maxn=10000000+5; 
int p[maxn],a[maxn]; 
int main(){ 
    int n,m=0,k; 
    cin>>n>>k; 
    for(int i=2;i<=n;i++){ 
        if(!p[i])
           a[m++]=i;  
        for(int j=0;j<m;j++){ 
            if(i*a[j]>n) 
              break; 
            p[i*a[j]]=1; 
            if(i%a[j]==0) //这里是关键,如果能除尽,就说明这个数能被更大的数构成,就直接跳出循环。
              break; 
        } 
    } 
    for(int i=1;i<=k;i++){ 
        int s; 
        cin>>s;
        if(s==1){
           cout<<"No"<<endl;
           continue;
        } 
        if(p[s])
           cout<<"No"<<endl;
        else 
           cout<<"Yes"<<endl;
    } 
    return 0; 
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值