算法競賽---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;
			}
		}
	}
	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;
}

以上就是我對等差素數列這個問題的所有總結和探討,對於一道普通的填空題,我覺得我自己挖的已經比較深了,嗯。。。先就這樣好了,我要開始刷下一題了~

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章