题意:
给出初始数字和结果数字,对初始数字进行变换,每次改变其中一位数字,并且每次改变完的数字必须是素数。问最少几次能把初始数字变换成结果数字。
解题过程:
首先因为数字一定是四位数,很明显的想到对10000以内的素数进行打表。筛法直接打个表就行啦。之后还要优化的一个地方就是在处理的过程中如果获得了结果数字,直接返回就好了,这样会省去很多时间,在代码里我有写到。
剩下的就是看代码啦,简单的BFS;
#include <iostream>
#include <cstdio>
#include <cmath>
#include <algorithm>
#include <queue>
#include <set>
#include <map>
#include <stack>
#include <string>
#include <list>
#include <cstdlib>
#include <memory>
#include <cstring>
#include <sstream>
#include <vector>
using namespace std;
#define INF 0x3f3f3f3f
#define PI 3.141592653579
#define FRER() freopen("input.txt" , "r" , stdin);
#define FREW() freopen("output.txt" , "w" , stdout);
#define QIO std::ios::sync_with_stdio(false)
const double eps = 1e-8;
typedef long long ll;
const int maxn = 10000+20;
bool prime[maxn+1];
bool vis[maxn];
void init()//素数打表
{
memset(prime , true , sizeof(prime));
prime[0] = prime[1] = false;
for(int i = 2; i < maxn ; i++)
if(prime[i])
{
if(i > maxn/i) continue;
for(int j = i * i ; j < maxn ; j += i)
prime[j] = false;
}
}
struct Node
{
int id , num;
};
void tostring(int a , int * s)
{
for(int i = 3 ; i >= 0 ; i--)
{ s[i] = a%10;a/=10; }
s[4] = 0;
}
int tointerger(int* s)
{
return s[0]*1000+s[1]*100+s[2]*10+s[3];
}
int BFS(int start , int end)
{
Node s{0 , start};
queue<Node> q;
q.push(s);
vis[start] = true;
int c[5];
while(!q.empty())
{
Node now = q.front();
// if(now.num == end)//不好的解决方法
// return now.id;
q.pop();
tostring(now.num , c);
for(int i = 0 ; i < 4 ; i++)
{
int change = c[i];
for(int j = 0; j <= 9 ; j++)
{
if(i == 0 && j == 0) continue;//保证四位数,第一位不能是零
c[i] = j;
int get = tointerger(c);
if(get == end) return now.id + 1;//出现了结果数字直接返回
if(!vis[get] && prime[get])
q.push((Node){now.id+1,get });
}
c[i] = change;
}
}
return -1;
}
int main()
{
// FRER();
// FREW();
QIO;
init();
int t;
cin >> t;
while(t--)
{
memset(vis, false , sizeof(vis));
int beg , end;
cin >> beg >> end;
if(beg == end) {printf("0\n");continue;}
int res = BFS(beg , end);
if(res == -1) printf("Impossible\n");
else printf("%d\n" , res);
}
}