题目大意
将一个素数变成另一个素数,一次只能变一位数,且每次也要变成素数,求最少的变换次数。
解题思路
预先处理出四位数的素数表,之后进行BFS。
对每个出队元素 a a a ,遍历前面打好的素数表,若有符合条件的 b b b (即从 a a a 到 b b b 只改变了一位数字),则入队。
判断改变是否合法的函数使得代码比较简洁:
bool canChange(int a, int b) {
int num = 0, ag, bg;
while (a) {
ag = a%10; a /= 10;
bg = b%10; b /= 10;
if (ag != bg) num++; //统计数字不一样的位数
}
return num == 1;
}
注意事项
1.写了个 getP()
函数要记得执行啊orz…
2.素数打表只需要存 [ 1000 , 9999 ] [1000,9999] [1000,9999] 内四位数的素数即可。
3.忘记写输出 i m p o s s i b l e impossible impossible 也给过了…
参考代码
//poj GCC
#include<iostream>
#include<vector>
#include<cstring>
#include<cstdio>
#include<climits>
#include<cmath>
#include<algorithm>
#include<queue>
#include<deque>
#include<map>
#include<set>
#include<stack>
#include<ctime>
using namespace std;
const int maxn = 1e5 + 10;
int readint() {
int x; scanf("%d", &x); return x;
}
bool isP[maxn], vis[maxn];
int prime[maxn];
int cnt = 0;
void getP() {
fill(isP, isP + maxn, true);
isP[1] = isP[0] = false;
for(int i = 2; i < maxn; i++) {
if (isP[i]) {
if (i >= 1000 && i < 1e4) prime[cnt++] = i; //只存[1000,9999]内的素数
for(int j = i + i; j < maxn; j += i) {
isP[j] = false;
}
}
}
}
bool canChange(int a, int b) {
int num = 0, ag, bg;
while (a) {
ag = a%10; a /= 10;
bg = b%10; b /= 10;
if (ag != bg) num++; //统计数字不一样的位数
}
return num == 1;
}
struct node{
int x, step;
};
queue<node> q;
int bfs(int a, int b) {
memset(vis, 0, sizeof(vis)); //每次要记得初始化vis数组
while (!q.empty()) q.pop();
q.push(node{
a, 0});
vis[a] = true;
node now;
while (!q.empty()) {
now = q.front();
q.pop();
if (now.x == b) return now.step;
for(int i = 0; i < cnt; i++) {
if (canChange(prime[i], now.x) && !vis[prime[i]]) {
q.push(node{
prime[i], now.step + 1});
vis[prime[i]] = true;
}
}
}
}
int main() {
int t = readint();
int a, b, ans;
getP(); //函数写了要记得执行orz
while (t--) {
a = readint();
b = readint();
ans = bfs(a, b);
printf("%d\n", ans);
}
return 0;
}