POJ 3126 Prime Path(素数打表+bfs)

题意: 输入两个数X1,X2,将x1变成X2,变化规则为:X1每次修改一位数,问修改多少次能够变成X2,并且X1每修改一次都必须是质数。输出最少次数,如果不可以输出Impossible。

例:1033 8179
1033
1733
3733
3739
3779
8779
8179

分析:有关素数判断的这类问题,我们第一时间会想到的素数打表,因此在程序中采用了筛选法,不懂的朋友可以自己上网看下相关资料。

首先对X1的个、十、百、千位依次进行变化,因为是四位数,每位数又由0~9十个数字组成,相当于排列组合,拿个例子来说吧。

1003,首先设它为基准值,变化个位数,可以构成1000、1001、1002、 1003 、1004~1009.变换完之后将这些结果保存下来,在进行十位数的变化。1013、 1023、 1033、 1043~1093,依次进行百位和千位的变化。然后又从这些变化过的数中重新设置基准值,进行变化,直到找到符合要求值为止。

当然在变化期间,肯定会重复变化某些值,所以要标记,相当于走地图一样走过之后就不在继续走了,同时要记录变化的步数。

下面是代码:

#include<cstdio>
#include<iostream>
#include<cmath>
#include<queue>
#include<string.h>
using namespace std;
int prime[10000]={0},vis[10000];   //prime用于与素数打表,vis保存变换到n素数的步数
int a[5]={1,10,100,1000};
int bfs(int x1,int x2)
{
    int next,j,i;
    queue<int>s;
    vis[x1]=0;
    s.push(x1);
    while(!s.empty())
    {
        next=s.front();
        s.pop();
        for(i=0;i<4;i++)
        {
            for(j=0;j<10;j++)
            {//这是大牛写的替换位数的方法,巧妙的与循环进行结合
                int x=next/(a[i]*10);  //将i+1位及之后的位置空出来

                int y=next%a[i];    //将要i+1之后的位数保存
                int temp=x*a[i]*10+j*a[i]+y; //替换掉第i位,并还原第i+1后面的数
                if(!prime[temp]&&temp>1000&&vis[temp]==-1)
                {
                    s.push(temp);
                    vis[temp]=vis[next]+1;
//                    printf("***%d    ",temp);
                    if(temp==x2)
                    {
                        return vis[temp];
                    }
                }
            }
        }

    }
    return -1;
}
int main()
{
    int i,j;
    for(i=2;i<=sqrt(10000);i++)  //素数打表
    {
        if(!prime[i])
        for(j=i*i;j<=9999;j+=i)
        {
            prime[j]=1;
        }
    }
    int n;
    while(scanf("%d",&n)!=EOF)
    {
        int i,x1,x2,temp;
        for(i=1;i<=n;i++)
        {
            scanf("%d%d",&x1,&x2);
            if(x1==x2)
            {
                printf("%d\n",0);
                continue;
            }
            memset(vis,-1,sizeof(vis));
            temp=bfs(x1,x2);
            if(temp!=-1)
            {
                printf("%d\n",temp);
            }
            else
            {
                printf("Impossible\n");
            }

        }
    }

}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值