[UESTC851]方老师与素数

Time Limit: 3000/1000MS (Java/Others)
Memory Limit: 65535/65535KB (Java/Others)

方老师最近很喜欢素数,他想玩一个游戏:

现在有两个4位的素数n和m,你一次可以改变n的一位数字,并且改变过后的新数字必须也是个素数,并且也不能有前导0。请问使n变为m最少需要多少步。

例如
n=1033
m=8179

那么可行的变化是:

1033
1733
3733
3739
3779
8779
8179
Input

第一行有一个整数T(T≤100),代表测试数据的组数。
对于每组数据,每行有两个4位素数N,M(没有前导0)

Output

对于每一组数据,如果能够得到m,输出最少的步数,否则输出Impossible

Sample Input

3
1033 8179
1373 8017
1033 1033

Sample Output

6
7
0

题解:
我先打了个素数表,发现1000~9999的素数个数只有不到1500,那么我们只要判断任意两个素数之间能不能互相转换,如果能的话,那就在他们呢之间连一条边,很幸运,然后将在并查集中将这两个素数所在的集合合并。然后对于每一对n,m,只需要判断n,m是否在一个集合内,如果不在就直接输出-1,否则用n为起点跑一边单源最短路,然后n到m的最短距离就是最少变换次数。

#include<iostream>
#include<cstdlib>
#include<cstdio>
#include<algorithm>
#include<queue>
#include<cstring>
#define LiangJiaJun main
#define INF 1999122700
using namespace std;
int T,ne,n,m;
int pri[1504],cnt,f[10004];
bool vis[10004];
int Find(int x){return f[x]==x?x:f[x]=Find(f[x]);}
int dis[10004],h[10004];
struct edge{int to,nt,w;}e[10004];
bool tip(int G, int L){
     int dif=0;
     while(G > 0 && L > 0){
        if((G % 10) != (L % 10)) dif++;
        G /= 10; L /= 10;
     }
     if(dif==1)return 1;
     return 0;
}
void add(int u,int v){
     e[++ne].to=v;
     e[ne].nt=h[u];h[u]=ne;
}
int shai(){
    vis[1]=1;
    for(int i=2;i<=10000;i++)
        for(int j=i+i;j<=10000;j+=i)vis[j]=1;
    for(int i=1000;i<10000;i++)if(!vis[i])pri[++cnt]=i;
    for(int i=1;i<=10000;i++)f[i]=i;
    for(int i=1;i<=cnt;i++){
        for(int j=i+1;j<=cnt;j++){
            if(tip(pri[i],pri[j])){
                int p=Find(pri[i]),q=Find(pri[j]);
                if(p!=q)f[p]=q;
                add(pri[i],pri[j]);
                add(pri[j],pri[i]);
            }
        }
    }
    return 0;
}
queue<int>q;
int spfa(int s,int t){
    memset(vis,0,sizeof(vis));
    for(int i=1;i<=10000;i++)dis[i]=INF;
    dis[s]=0;q.push(s);vis[s]=1;
    while(!q.empty()){
        int x=q.front();q.pop();
        for(int i=h[x];i;i=e[i].nt){
            if( dis[e[i].to]>dis[x]+1){
                dis[e[i].to]=dis[x]+1;
                if(!vis[e[i].to]){
                    vis[e[i].to]=1;
                    q.push(e[i].to);
                }
            }
        }
    }
    return dis[t];
}
int w33ha(){
    scanf("%d%d",&n,&m);
    if(Find(n)!=Find(m))return puts("-1"),0;
    if(n==m)return puts("0"),0;
    printf("%d\n",spfa(n,m));
    return 0;
}
int LiangJiaJun(){
    scanf("%d",&T);
    shai();
    while(T--)w33ha();
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值