题目描述
现给定两个 四位素数 a,b。 你可以执行多次下面的操作:
修改数字 a 的某一位, 使其成为另一个 四位素数b。
例如,1033→1733,其中 1033 与 1733 均为素数。
问至少多少次变换后能从 a 得到 b ? 或回答不可能。
输入
第一行一个数字 T,表示接下来将会有 T 组数据。
接下来包含 T 行,每行包含用空格分开的两个 四位素数 a,b。
输出 T 行,如果可以,输出最小变换次数。反之输出 −1。
输出
输出 T 行,如果可以,输出最小变换次数。反之输出 −1。
样例输入
2 1033 1033 1033 8779
样例输出
0 5
提示
1033-->1733-->3733-->3739-->3779-->8779
思路:
求a变换为b的最小变换次数,且每次只能变换一位数,可以使用bfs去搜索,根据bfs的性质,最先搜索到的一定为最优解。题目要求对变换后的数也为素数,所以要对四位数的素数进行预处理。
#include <iostream>
#include <queue>
#include <cstring>
using namespace std;
const int N=1e5+10;
bool st[N],su[N];
struct xxx ///统计搜到的数以及变换的次数
{
int w;
int d;
};
int xx(int x) ///素数的判定
{
if(x==1) return 0;
for(int i=2;i<=x/i;i++)
{
if(x%i==0) return 0;
}
return 1;
}
void bfs(int a,int b)
{
memset(st,false,sizeof(st)); ///对st数组预处理,st数组统计这个数是否被搜过
queue<xxx> q;
q.push({a,0});
st[a]=true;
while(q.size())
{
xxx z=q.front();
q.pop();
if(z.w==b) ///搜到b就输出变换的次数
{
cout << z.d << endl;
return ;
}
int a1=z.w%10;
int a2=z.w/10%10;
int a3=z.w/100%10;
int a4=z.w/1000;
for(int i=0;i<=9;i++) ///对个位的变换
{
int y=a4*1000+a3*100+a2*10+i;
if(y==z.w) continue;
else
{
if(!st[y]&&su[y])
{
q.push({y,z.d+1});
}
}
}
for(int i=0;i<=9;i++) ///对十位的变换
{
int y=a4*1000+a3*100+i*10+a1;
if(y==z.w) continue;
else
{
if(!st[y]&&su[y])
{
q.push({y,z.d+1});
st[y]=true;
}
}
}
for(int i=0;i<=9;i++) ///对百位的变换
{
int y=a4*1000+i*100+a2*10+a1;
if(y==z.w) continue;
else
{
if(!st[y]&&su[y])
{
q.push({y,z.d+1});
st[y]=true;
}
}
}
for(int i=1;i<=9;i++) ///对千位的变换(千位不为0)
{
int y=i*1000+a3*100+a2*10+a1;
if(y==z.w) continue;
else
{
if(!st[y]&&su[y])
{
q.push({y,z.d+1});
st[y]=true;
}
}
}
}
cout << "-1" << endl; ///搜不到b就输出-1
return ;
}
int main()
{
for(int i=1000;i<=9999;i++) ///对四位数的素数进行预处理
{
if(xx(i)==1)
su[i]=true;
else
su[i]=false;
}
int n;
cin >> n;
while(n--)
{
int a,b;
cin >> a >> b;
bfs(a,b);
}
return 0;
}