题目链接:vjudge.net/problem/POJ... 题目大意:将一个4位正整数质数,每次改动一位数字,转为另一个四位正整数质数,并且每次改变玩的数字也是质数,找到最小改动次数,可能找不到。
最短路径问题,考虑BFS,做一个质数表,然后四位数,依次枚举即可
枚举过程: 用双循环,第一层枚举4个数位,第二层枚举0-9,把4个数位先分离出来,然后枚举,再还原回去。
易踩坑: memsetmemset(ptr, value, size) 的第二个参数 value 虽然是 int,但它只取低 8 位(一个字节) ,然后把内存的每个字节都设成这个值。 所以如果我的质数表是int prime10000 就会导致,设置出来的结果是16843009,如果我的质数表是bool prime10000,就正常了,因为bool只有一个字节,设置成0x01正好。
AC代码:
c++
#include <algorithm>
#include <iostream>
#include <set>
#include <vector>
#include <unordered_map>
#include <queue>
#include <cstring>
using namespace std;
bool prime[10000];
void set_prime() {
memset(prime, true, sizeof(prime));
prime[0] = false;
prime[1] = false;
for (int i = 2; i < 10000; i++) {
if (prime[i] == 1) {
for (int j = i + i; j < 10000; j += i) {
prime[j] = 0;
}
}
}
}
int dist[10000];
int bfs(int start, int end) {
// 一共4位数,个位在1,3,5,7,9中间找 因为4位数质数的个位不可能是0,2,4,5,6,8
// 十位在 0到 9中间
// 百位在 0 ~ 9 中间
// 千位在1 ~ 9中间找
if (start == end) {
return 0;
}
memset(dist, -1, sizeof(dist));
queue<int> q;
q.push(start);
dist[start] = 0;
int pow10[4] = {1000, 100, 10, 1};
while (!q.empty()) {
int cur = q.front();
q.pop();
if (cur == end) {
return dist[cur];
}
int d[4];
d[0] = cur / 1000;
d[1] = cur / 100 % 10;
d[2] = cur / 10 % 10;
d[3] = cur % 10;
// 枚举4个数位
for (int i = 0; i < 4; i++) {
int old = d[i];
for (int j = 0; j <= 9; j++) {
if (j == old) {
continue;
}
if (i == 0 && j == 0) {
continue;
}
if (i == 3 && (j % 2 == 0 || j == 5)) {
continue;
}
int next = cur + (j - old) * pow10[i];
if (next < 1000 || next > 9999) {
continue;
}
if (prime[next] && dist[next] == -1) {
dist[next] = dist[cur] + 1;
q.push(next);
}
}
}
}
return -1;
}
int main() {
set_prime();
// for (int i = 0; i < 100; i++) {
// cout << i << ":" << prime[i] << endl;
// }
int n;
cin >> n;
while (n--) {
int start, end;
cin >> start >> end;
int ans = bfs(start, end);
if (ans == -1) {
cout << "Impossible" << endl;
} else {
cout << ans << endl;
}
}
}