算法竞赛---day3(等差素数列)

静下心来,慢慢调整自己的生活状态,一切都会好的。。。
关于等差素数列的问题,我们今天再做最后一次讨论,集百家之长,悟绝妙之道。。。
a.素数筛选法的精简进阶版本:(素数打表,减少不必要的重复计算)

//#include<bits/stdc++.h> 
#include<iostream>
using namespace std;
const int maxn=1000005;
int prime[maxn];
void isprime(int n){
	for(int i=2;i*i<=n;i++){
		if(!prime[i]){
			for(int j=i*i;j<=n;j+=i){
				prime[j]=1;
			}
		}
	}
}
int main(){
	isprime(1000000);
	for(int d=1;d<=1000;d++){
		for(int i=2;i<=100000;i++){
			int j;
			for(j=0;j<10;j++){
				if(prime[i+j*d]){
					break;
				}
			}
			if(j==10){
				cout<<d<<endl;
				cout<<i<<endl;
				return 0;
			}
		}
	}
}

b.dfs版本:素数打表,用for循环从2开始递增,表示公差,里面的for循环表示从数j开始,用搜索判断是否数列是从j开始以i为公差,长度为10的等差数列。

//#include<bits/stdc++.h> 
#include<iostream>
#include<cmath>
using namespace std;
int m,flag,k,s,prime[101000];
void dfs(int x,int n,int d){
	if(n==9){
		s=x;
		flag=1;
		return ;
	}
	if(flag==1){
		return ;
	}
	if(k==1){
		return ;
	}
	for(int j=x+1;j<=m;j++){
		if(prime[j]-prime[x]>d){
			k=1;
			return ;
		}
		if(prime[j]-prime[x]==d){
			dfs(j,n+1,d);
		}
	}
}
int main(){
	int i,j;
	m=0;
	for(i=2;i<=100000;i++){
		int p=0;
		for(j=2;j<=sqrt(i);j++){
			if(i%j==0){
				p=1;
				break;
			}
		}
		if(!p){
			prime[m++]=i;
		}
	}
	flag=0;
	for(i=2;i<=1000;i++){
		for(j=2;j<m;j++){
			k=0;
			dfs(j,0,i);
			if(flag==1){
				cout<<i;
				break;
			}
		}
		if(flag){
			break;
		}
	}
	return 0;
}

c.总结dfs这种常规方法和特殊的素数筛方法,我们升级一下代码:

//#include<bits/stdc++.h> 
#include<iostream>
using namespace std;
int m,flag,k,s,prime[10100],p[10100];
void dfs(int x,int n,int d){
	if(n==9){
		s=x;
		flag=1;
		return ;
	}
	if(flag==1){
		return ;
	}
	if(k==1){
		return ;
	}
	for(int j=x+1;j<=m;j++){
		if(prime[j]-prime[x]>d){
			k=1;
			return ;
		}
		if(prime[j]-prime[x]==d){
			dfs(j,n+1,d);
		}
	}
}
void isprime(){
	for(int i=2;i<=10000;i++){
		if(p[i]){
			continue;
		}
		for(int j=i*i;j<=10000;j+=i){
			p[j]=1;//减少重复判断剔除合数。
		}
		prime[m++]=i;
	}
}
int main(){
	int i,j;
	isprime();
	flag=0;
	for(i=2;i<=1000;i++){
		for(j=2;j<=m;j++){
			k=0;
			dfs(j,0,i);
			if(flag==1){
				cout<<i;
				break;
			}
		}
		if(flag){
			break;
		}
	}
	return 0;
}

Tips:
为啥在isprime()里的取值范围必须是10000???
因为i要取到一个很大的值,虽然这个值可能不是素数,但因为需要判断,所以要取到最大素数的所在位置。
d.用6的规律来剪枝,使得算法耗时降为原来的1/3。

//#include<bits/stdc++.h> 
#include<iostream>
using namespace std;
int m,flag,k,s,prime[10100],p[10100];
void dfs(int x,int n,int d){
	if(n==9){
		s=x;
		flag=1;
		return ;
	}
	if(flag==1){
		return ;
	}
	if(k==1){
		return ;
	}
	for(int j=x+1;j<=m;j++){
		if(prime[j]-prime[x]>d){
			k=1;
			return ;
		}
		if(prime[j]-prime[x]==d){
			dfs(j,n+1,d);
		}
	}
}
bool isprime2(int num){
	if(num==2||num==3){
		return 1;
	}
	if(num%6!=1&&num%6!=5){
		return 0;
	}
	for(int i=5;i*i<=num;i+=6){
		if(num%i==0||num%(i+2)==0){
			return 0; 
		}
	}
	return 1;
}
void isprime(){
	for(int i=2;i<=10000;i++){
		if(isprime2(i))
		prime[m++]=i;
	}
}
int main(){
	int i,j;
	isprime();
	flag=0;
	for(i=2;i<=1000;i++){
		for(j=2;j<=m;j++){
			k=0;
			dfs(j,0,i);
			if(flag==1){
				cout<<i;
				break;
			}
		}
		if(flag){
			break;
		}
	}
	return 0;
}

e.根据素数规律从30开始取公d为6的倍数,即d+=6,再次优化代码。

//#include<bits/stdc++.h> 
#include<iostream>
using namespace std;
int m,flag,k,s,prime[10100],p[10100];
void dfs(int x,int n,int d){
	if(n==9){
		s=x;
		flag=1;
		return ;
	}
	if(flag==1){
		return ;
	}
	if(k==1){
		return ;
	}
	for(int j=x+1;j<=m;j++){
		if(prime[j]-prime[x]>d){
			k=1;
			return ;
		}
		if(prime[j]-prime[x]==d){
			dfs(j,n+1,d);
		}
	}
}
bool isprime2(int num){
	if(num==2||num==3){
		return 1;
	}
	if(num%6!=1&&num%6!=5){
		return 0;
	}
	for(int i=5;i*i<=num;i+=6){
		if(num%i==0||num%(i+2)==0){
			return 0; 
		}
	}
	return 1;
}
void isprime(){
	for(int i=2;i<=10000;i++){
		if(isprime2(i))
		prime[m++]=i;
	}
}
int main(){
	int i,j;
	isprime();
	flag=0;
	for(i=30;i<=1000;i+=6){
		for(j=2;j<=m;j++){
			k=0;
			dfs(j,0,i);
			if(flag==1){
				cout<<i;
				break;
			}
		}
		if(flag){
			break;
		}
	}
	return 0;
}

以上就是我对等差素数列这个问题的所有总结和探讨,对于一道普通的填空题,我觉得我自己挖的已经比较深了,嗯。。。先就这样好了,我要开始刷下一题了~

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值