这道题目要在解决问题之前先预处理出一个四位数的质数表,由于范围很小,只需要枚举1000~9999并用O(√n)的质数判断函数进行验证即可,当然,用线性筛或除余法也是可以的(此题时间充裕,不建议用MR素数判断)。
然后便是一个BFS,对于当前数字,只要枚举每一个它能变成的质数,判断是否已操作过,若未操作过则将其加入队列即可。
代码如下:
#include<cstdio>
#include<algorithm>
#include<iostream>
#include<cstring>
#include<cmath>
#include<queue>
#define max(x,y) (x>y?x:y)
#define min(x,y) (x<y?x:y)
#define LL long long
using namespace std;
int n,m;
bool vis[10000],Prime[10000];
struct BFS
{
int v,step;//v存储数字,step存储步数
};
queue<BFS> q,q_;
int read()
{
int x=0,f=1;char ch=getchar();
while((ch<'0'||ch>'9')&&ch!='-') ch=getchar();
if(ch=='-') f=-1,ch=getchar();
while(ch>='0'&&ch<='9') (x*=10)+=ch-'0',ch=getchar();
return x*=f;
}
void write(int x)
{
if(x<0) putchar('-'),x=-x;
if(x>9) write(x/10);
putchar(x%10+'0');
}
bool Is_prime(int x) {for(int i=2;i*i<=x;i++) if(!(x%i)) return false;return true;}//O(√n)的质数判断函数
void Find_prime() {for(int i=1000;i<10000;i++) Prime[i]=Is_prime(i);}//枚举每一个四位数
void bfs()//BFS
{
if(q.empty()) return;//若队列空了则退出函数(理论上来说是不会出现这种情况的)
if(q.front().v==m) {write(q.front().step),putchar('\n');return;}//达成目标就输出步数(记得换行)
for(int t=1;t<=1000;t*=10) for(int i=0;i<=9;i++) {int nx=q.front().v-(q.front().v/t)%10*t+i*t;if(!vis[nx]&&Prime[nx]) vis[nx]=true,q.push({nx,q.front().step+1});}//枚举当前数字能变成的每一个质数
q.pop(),bfs();//将当前状态从队列中取出,BFS下一个状态
}
int main()
{
memset(Prime,false,sizeof(Prime));
Find_prime();//预处理出四位数的质数表
int T=read();
while(T--)
{
n=read(),m=read();
memset(vis,false,sizeof(vis));
q=q_,q.push({n,0}),vis[n]=true;//记得在新的一次BFS前清空队列
bfs();
}
return 0;
}
版权声明:转载请注明地址