Prime Path POJ - 3126 (最短路)
hh学长酷爱素数,他经常自娱自乐,随机挑选两个四位的素数a,b。
游戏规则是:a可以通过改变某一位上的数字使其变成c,但只有当c也是四位的素数时才能进行这种改变。
hh学长可以很轻松的算出a最少经过多少次变化使其变为b,所以他相信你也可以。
例如:1033 -> 8179
1033
1733
3733
3739
3779
8779
8179
最少变换了6次。
Input
第一行输入整数T,表示样例数。 (T <= 100)
每个样例输入两个四位的素数a,b。(没有前导零)
Output
对于每个样例,输出最少变换次数,如果无法变换成b则输出"Impossible"。
Sample Input
3
1033 8179
1373 8017
1033 1033
Sample Output
6
7
0
预处理出来所有的素数,只有一千多个,可以在任意两个素数之间建一条边,可以经过一次变换边权为1,否则边权为0。
如果a==b那么直接输出0,如果b不是素数输出impossible,其他情况在边权为1之间的边中跑一遍最短路(如果a不是素数还要在a与所有素数之间建一条边)
#include<iostream>
#include<algorithm>
#include<vector>
#include<cstring>
#include<queue>
#include<cstdio>
#include<map>
using namespace std;
#define pii pair<int,int>
typedef long long ll;
const int N=10010,M=2000;
int n,p[10];
bool prim[N];
vector<int> res;
bool g[N][N];//开int会MLE
bool check(int x,int y)//判断是否可以经过一次变换,用差值判断会错
{
int cnt=0;
while(x)
{
if(x%10==y%10) cnt++;
x/=10;y/=10;
}
return cnt==3;
}
void init()
{
prim[1]=1;
for(int i=2;i<=N/i;i++)
{
if(!prim[i])
for(int j=i*i;j<N;j+=i)
prim[j]=1;
}
for(int i=1000;i<10000;i++)
if(!prim[i]) res.push_back(i);
for(int i=0;i<res.size();i++)//建边
for(int j=i+1;j<res.size();j++)
if(check(res[i],res[j])) g[i][j]=g[j][i]=1;
}
int dist[M];
bool vis[M];
void dij(int st,int en)
{
memset(dist,0x3f,sizeof dist);
priority_queue<pii,vector<pii>,greater<pii> > q;
dist[st]=0;
q.push({0,st});
memset(vis,0,sizeof vis);
while(q.size())
{
int u=q.top().second;
q.pop();
if(u==en) break;
if(vis[u]) continue;
for(int i=0;i<res.size();i++)
{
if(g[u][i]&&dist[i]>dist[u]+1)
{
dist[i]=dist[u]+1;
q.push({dist[u]+1,i});
}
}
vis[u]=1;
}
}
int main()
{
init();
int t;
cin>>t;
while(t--)
{
int a,b;
cin>>a>>b;
int l=lower_bound(res.begin(),res.end(),a)-res.begin();
int r=lower_bound(res.begin(),res.end(),b)-res.begin();
if(a==b) puts("0");
else if(prim[b]) puts("Impossible");
else
{
if(prim[a])
{
for(int i=0;i<res.size();i++) g[res.size()][i]=(check(a,res[i])?1:0);
l=res.size();
}
dij(l,r);
if(dist[r]!=0x3f3f3f3f) cout<<dist[r]<<endl;
else puts("Impossible");
}
}
}```