题目连接: Prime Path
题目:
给你两个四位的素数a,b。
a可以改变某一位上的数字变成c,但只有当c也是四位的素数时才能进行这种改变。
请你计算a最少经过多少次上述变换才能变成b。
例如:1033 -> 8179
1033 -> 1733 -> 3733 -> 3739 -> 3779 ->8779 -> 8179
最少变换了6次。
Input
第一行输入整数T,表示样例数。 (T <= 100)
每个样例输入两个四位的素数a,b。(没有前导零)
Output
对于每个样例,输出最少变换次数,如果无法变换成b则输出"Impossible"。
Sample Input
3
1033 8179
1373 8017
1033 1033
Sample Output
6
7
0
解题思路:
BFS思想, 将最开始的那个数字每一位尝试0-9(首位1-9)变换, 如果变换后仍为素数, 推入队列, 直到队列空或者达到目标数字.
AC代码:
#include <bits/stdc++.h>
#define ll long long
using namespace std;
bool num[10005]; //用于记录1000-9999各个数字是否为质数, 1是 0不是
bool vis[10005]; //用于记录当前数字是否已经出现过
int n, m; int ans; //初始数字m, 目标数字n, 变化次数ans
queue<int> q;
void first() //预处理操作, 把1000-9999内素数进行标记
{
for (int i = 1000; i <= 9999; i++) {
for (int j = 2; j <= sqrt(i); j++) {
if (i % j == 0) goto here;
}
num[i] = 1;
here:;
}
}
//1033 / 100 = 10 1033 % 100 = 33
bool fact() //BFS
{
ans = -1; //至于为什么一开始标记成-1, 请想一下
while (!q.empty()) {
int t = q.size(); ans++; //每次循环原先队列有的元素, 即保证当前层的元素都是上一步变化产生的
while (t--) {
int op = q.front(); q.pop();
if (op == m) return 1;
int temp; //for循环处的代码就是分别改变 千位 百位 十位 个位的数字, 如果改变后的数字是质数且未出现, 则推入队列
for (int i = 0; i <= 9; i++) {
if (i != 0) { //千位特判
temp = i * 1000 + op % 1000;
if (!vis[temp] && num[temp]) { q.push(temp); vis[temp] = 1; }
}
temp = i * 100 + op % 100 + op / 1000 * 1000;
if (!vis[temp] && num[temp]) { q.push(temp); vis[temp] = 1; }
temp = i * 10 + op % 10 + op / 100 * 100;
if (!vis[temp] && num[temp]) { q.push(temp); vis[temp] = 1; }
temp = i + op / 10 * 10;
if (!vis[temp] && num[temp]) { q.push(temp); vis[temp] = 1; }
}
}
}
return 0; //队列已空, 无法得到目标数字
}
int main(void)
{
first(); //预处理
int t; cin >> t;
while (t--) {
memset(vis, 0, sizeof(vis)); while (!q.empty()) q.pop();
scanf("%d %d", &n, &m); vis[n] = 1;
q.push(n);
if (fact()) cout << ans << endl;
else cout << "Impossible" << endl;
}
return 0;
}
如果不理解fact()函数中跑当前层的操作, 可以考虑改成结构体, 在其内加一个int step;表示当前操作次数, 当操作到这个数字时, 让得到的新数字的step’ = step+1, 最后输出得到目标数字时的step值也可.