Problem
The ministers of the cabinet were quite upset by the message from the Chief of Security stating that they would all have to change the four-digit room numbers on their offices.
— It is a matter of security to change such things every now and then, to keep the enemy in the dark.
— But look, I have chosen my number 1033 for good reasons. I am the Prime minister, you know!
— I know, so therefore your new number 8179 is also a prime. You will just have to paste four new digits over the four old ones on your office door.
— No, it’s not that simple. Suppose that I change the first digit to an 8, then the number will read 8033 which is not a prime!
— I see, being the prime minister you cannot stand having a non-prime number on your door even for a few seconds.
— Correct! So I must invent a scheme for going from 1033 to 8179 by a path of prime numbers where only one digit is changed from one prime to the next prime.
Now, the minister of finance, who had been eavesdropping, intervened.
— No unnecessary expenditure, please! I happen to know that the price of a digit is one pound.
— Hmm, in that case I need a computer program to minimize the cost. You don’t know some very cheap software gurus, do you?
— In fact, I do. You see, there is this programming contest going on… Help the prime minister to find the cheapest prime path between any two given four-digit primes! The first digit must be nonzero, of course. Here is a solution in the case above.
1033
1733
3733
3739
3779
8779
8179
The cost of this solution is 6 pounds. Note that the digit 1 which got pasted over in step 2 can not be reused in the last step – a new 1 must be purchased.
Input
One line with a positive number: the number of test cases (at most 100). Then for each test case, one line with two numbers separated by a blank. Both numbers are four-digit primes (without leading zeros).
Output
One line for each case, either with a number stating the minimal cost or containing the word Impossible.
Sample Input
3
1033 8179
1373 8017
1033 1033
Sample Output
6
7
0
题意:
给定两个四位数,前者较小,后者较大,求从前一个数变到后一个数最少需要几步。
改变的原则是每次只能改变某一位上的一个数,而且每次改变得到的必须是一个素数。
先将1000到9999之间的素数运用筛法打个表(朴素筛法就行),之后将prime path上的每个素数看作每个节点,抽象成bfs求最小步数问题。
注意从一个数走一步变成另一个素数时,两个数只能有一位数字差别,由于题设要求最小步数,则在bfs每次将队头扩展时应当从大到小来枚举素数(因为初始输入的初状态和末状态分别为一个较小的数和一个较大的素数)
朴素筛法打表代码:
void init()
{
for(int i=2;i<=9999;++i)
{
if(!st1[i]&&i>=1000) primes[cnt++]=i;
for(int j=2*i;j<=9999;j+=i)
{
st1[j]=true;
}
}
}
判断两个四位数是否只相差一位函数:
bool judge(int a, int b)
{
int s = 0;
while(a)
{
if (a%10!=b%10) ++s;
a/=10,b/=10;
}
if(s==1) return true;
return false;
}
总代码如下:
#include<iostream>
#include<cstring>
#include<queue>
using namespace std;
int t;
const int N = 10010;
int primes[N], cnt;
int a[N], x;
bool st1[N],st2[N];//素数、广搜 判重数组
int p1, p2;
struct node
{
int val;//值
int step;//步数
};
queue<node> q;
void init()//朴素筛法筛素数
{
for(int i=2;i<=9999;++i)
{
if(!st1[i]&&i>=1000) primes[cnt++]=i;
for(int j=2*i;j<=9999;j+=i)
{
st1[j]=true;
}
}
}
bool judge(int a, int b)//判断两个数是否只相差一位
{
int s = 0;
while(a)
{
if (a%10!=b%10) ++s;
a/=10,b/=10;
}
if(s==1) return true;//只有一位区别才返回true
return false;
}
void bfs()
{
q.push({ p1,0 });
st2[p1] = true;
while (!q.empty())
{
node tmp = q.front();
q.pop();
if (tmp.val == p2)
{
cout<<tmp.step<<endl;
return ;
}
for (int i = cnt - 1; i >= 0; --i)
{
int v = tmp.val,tim = tmp.step;
if (!st2[primes[i]] && judge(v, primes[i]))
{
st2[primes[i]] = true;
v = primes[i];
tim++;
q.push({v,tim});
}
}
}
cout<<"impossible"<<endl;
}
int main()
{
init();
cin >> t;
while (t--)
{
while(!q.empty()) q.pop();
memset(st2,false,sizeof st2);
cin >> p1 >> p2;
bfs();
}
return 0;
}