http://poj.org/problem?id=3126
每次给出a,b两个素数,每一次都可以把前一个数转换成另外一个四位素数,但是有且仅有一个数位不同。问从a转换到b,需要的最少转换步数。
首先求出从所有的四位素数,然后从a开始扩展与之有且只有一个数位不同的四位素数,最先扩展到b所需要的步数就是答案。
怎么求四位素数,我这里用了区间筛选素数,其实无论哪一种方法都是可以的,这里就当练习一下区间筛选素数吧。
#include<cstdio>
#include<cstring>
#include<iostream>
#include<string>
#include<cmath>
#include<algorithm>
#include<queue>
#define ll __int64
#define INF 0x3f3f3f3f
#define N 10000000
using namespace std;
bool is_prime_small[N], is_prime[N];
int prime[N], Flag[N];
int a, b, n, cnt, Min, u, site;
struct Node
{
int num;
int step;
};
queue<Node> q;
struct Node P, p;
void segment_sieve(int a, int b)//a,b很大的时候要开ll,循环中i*i前面要加(ll)
{
for (int i = 0; i * i < b; i++)
{
is_prime_small[i] = true;
}
for (int i = 0; i < b - a; i++) is_prime[i] = true;
for (int i = 2; i * i < b; i++)
{
if (is_prime_small[i])
{
for (int j = 2 * i; j * j < b ; j += i) is_prime_small[i] = false;
int tmp;
if (a % i == 0)
{
if (a == i) tmp = 2*i;
else tmp = a;
}
else tmp = (a/i+1)*i; // tmp是大于等于a的最小的i的倍数(不包括i本身)
for (int j = tmp; j < b; j += i)
{
is_prime[j-a] = false;//由于可能很大,所以充分利用数组空间
}
}
}
}
bool ok(int x, int y)
{
int tot = 0, p1, p2;
while (x > 0)
{
p1 = x % 10;
p2 = y % 10;
x = x / 10;
y = y / 10;
if (p1 != p2) tot++;
}
if (tot != 1) return false;
else return true;
}
void bfs()
{
while (!q.empty()) q.pop();
p.num = a;
p.step = 1;
q.push(p);
for (int i = 0; i < cnt; i++)
if (prime[i] == a)
{
site = i;
break;
}
memset(Flag, 0, sizeof(Flag));
Flag[site] = 1;
u = 0;
while (!q.empty())
{
p = q.front();
q.pop();
for (int i = 0; i < cnt; i++)
if (Flag[i] == 0 && ok(p.num, prime[i]))
{
Flag[i] = 1;
P.num = prime[i];
P.step = p.step+1;
if (P.num == b)
{
Min = p.step;
u = 1;
break;
}
q.push(P);
}
if (u == 1) break;
}
}
int main()
{
scanf("%d", &n);
cnt = 0;
segment_sieve(1000, 10000);
for (int i = 1000; i < 10000; i++)
if (is_prime[i-1000])
{
prime[cnt++] = i;
}
for (int i = 0; i < n; i++)
{
scanf("%d%d", &a, &b);
Min = INF;
if (a == b) Min = 0;
else
bfs();
if (Min != INF) printf("%d\n", Min);
else printf("Impossible\n");
}
return 0;
}