题目链接
题意就是给一个四位素数,让找一个最短路径让它变成目标素数。要注意路径中的所有数都必须是四位素数,且一次只能改动一位数字。
考虑到一个数最多只有40种后继状态,所以可以先将1000到10000之间的素数选出来,然后BFS一遍就行了。
具体实现见代码及注释。
#include<cstring>
#include<queue>
#include<cstdio>
#include<vector>
using namespace std;
int fi,en; //fi为开始状态,en为目标状态。
int d[10000];
bool vis[10000],nprime[10000];
void bfs(){
memset(vis,0,sizeof(vis));
memset(d,0,sizeof(0));
queue<int> que;
d[fi]=0;
vis[fi]=1;
que.push(fi);
int v[4];
while(!que.empty()){
int n=que.front();
que.pop();
if(n==en){printf("%d\n",d[n]);return;}
for(int i=0;i<4;i++){
for(int j=0;j<10;j++){
v[0]=n%10000/1000;
v[1]=n%1000/100;
v[2]=n%100/10;
v[3]=n%10/1; //将数分解为四位数
v[i]=j; //将第i位修改为j
int u=v[0]*1000+v[1]*100+v[2]*10+v[3];//修改后得到的四位数
if(nprime[u]||vis[u]||u<1000) continue;
//不是素数,已经访问过,小于1000,都不符合
vis[u]=1;
d[u]=d[n]+1; //记录距离
que.push(u);
}
}
}
}
void get_form(){ //构造素数表
memset(nprime,0,sizeof(nprime));
for(int i=2;i<=9999;i++){
for(int j=i<<1;j<=9999;j+=i) nprime[j]=1; //筛选掉不是素数的数。
}
}
int main(){
int t;
scanf("%d",&t);
get_form();
while(t--){
scanf("%d%d",&fi,&en);
bfs();
}
return 0;
}