题目链接:http://poj.org/problem?id=3126
题意:给定两个范围在【1000,9999】的两个素数,问从一个素数到另外一个素数需要多少歩,每次只能改变一个数,且过渡的数必须是素数。例如:1033
——1733——3733——3739——3779——8779——8179。
分析:很经典的广搜题,谈到广搜不得不说的是已经搜索过的状态的标记,可以用visit数组,然后就是必须得是素数,可以先预处理,打印一张素数表,方便以后询问。注意四位数不能有前导0。其他的见代码:
code:
#include<cstdio>
#include<cstring>
#include<queue>
using namespace std;
struct node{int x,step;}s;
const int MAXN=10000;
bool is_prime[MAXN];
int visit[MAXN];
int begin,end;
void sieve(int n){
for(int i=0;i<=n;i++)is_prime[i]=true;
is_prime[0]=is_prime[1]=false;
for(int i=2;i<=n;++i){
if(is_prime[i]){
for(int j=2*i;j<=n;j+=i)
is_prime[j]=false;
}
}
}//素数筛方便以后询问
void bfs(){
memset(visit,0,sizeof(visit));
visit[begin]=1;
queue<node>q;
while(!q.empty())q.pop();
s.step=0;s.x=begin;//初始化
q.push(s);
while(!q.empty()){
node ne=q.front();q.pop();
if(ne.x==end){
printf("%d\n",ne.step);
return ;
}
int a[4];//将一个完整的四位数分解成四个数字
for(int i=3;i>=0;--i){
a[i]=ne.x%10;
ne.x/=10;
}
for(int i=0;i<4;++i){
int j=(i==0?1:0);//如果是首位,那么不能为0,故从1开始枚举。
for(;j<=9;++j){
int temp=a[i];
a[i]=j;
int num=a[0]*1000+a[1]*100+a[2]*10+a[3];//将分散的四个数字还原成一个完整的四位数
a[i]=temp;//将改变的数字复原,有点回溯的味道
if(!visit[num]&&is_prime[num]){
node no;no.step=ne.step+1;no.x=num;
visit[num]=1;
q.push(no);
}
}
}
}
}
int main(){
sieve(MAXN);
int T;scanf("%d",&T);
while(T--){
scanf("%d%d",&begin,&end);
bfs();
}
}