Prime Path
题目大概意思:
给出两个素数 和 ( ),每次可以修改 的四位十进制数字中的一位数字,使其变为另外一个四位数的素数,问最少需要修改几次可以把 变为 . 若不可能则输出 “ ”.
分析:
首先用埃式素数筛在 的时间复杂度内,或线性素数筛在 的时间复杂度内筛选出所有的四位的素数,这样可以得到 个素数。
然后对这些素数两两判断,如果可以通过修改一位互相转换,则连一条双向边。这一步时间复杂度为 .
最后进行宽度优先搜索,计算 到 的最短路径长度,每次宽度优先搜索的时间复杂度为 .
下面贴代码:
#include <cstring>
#include <cstdio>
#include <vector>
#include <queue>
using namespace std;
const int MAX_N = 10001;
struct P
{
int d;
int num;
P(const int& d = 0, const int& num = 0)
:d(d), num(num) {}
};
bool is_prime[MAX_N];
int primes[1062], pcnt;
vector<int> G[MAX_N];
bool used[MAX_N];
void init();
void getprime(const int N);
void add_edge(const int u, const int v);
int bfs(const int S, const int T);
int main()
{
init();
int T, a, b;
scanf("%d", &T);
while (T--)
{
scanf("%d%d", &a, &b);
int ans = bfs(a, b);
if (~ans)
{
printf("%d\n", ans);
}
else
{
printf("Impossible\n");
}
}
return 0;
}
void add_edge(const int u, const int v)
{
G[u].push_back(v);
G[v].push_back(u);
}
int bfs(const int S, const int T)
{
memset(used + 1000, false, sizeof(used) - 1000);
queue<P> q;
used[S] = true;
q.push(P(0, S));
while (!q.empty())
{
P cur = q.front();
q.pop();
if (cur.num == T) return cur.d;
const vector<int>& v = G[cur.num];
P nxt(cur.d + 1);
for (int i = 0; i < v.size(); ++i)
{
nxt.num = v[i];
if (!used[nxt.num])
{
used[nxt.num] = true;
q.push(nxt);
}
}
}
return -1;
}
void init()
{
getprime(MAX_N);
memset(is_prime, false, 1000 * sizeof(bool));
for (int i = 1; i < pcnt; ++i)
{
const int& ci = primes[i];
for (int j = 0; j < i; ++j)
{
int pi = ci;
int pj = primes[j];
int unsame = 0;
for (int k = 0; k < 4; ++k)
{
if (pi % 10 != pj % 10)
{
++unsame;
}
pi /= 10;
pj /= 10;
}
if (unsame <= 1)
{
add_edge(ci, primes[j]);
}
}
}
}
void getprime(const int N)
{
memset(is_prime + 2, true, N - 2);
for (int i = 2; i < N; ++i)
{
if (is_prime[i])
{
if (i > 1000) primes[pcnt++] = i;
for (int j = i << 1; j < N; j += i)
{
is_prime[j] = false;
}
}
}
}