hdu 1973 Prime Path (bfs)

HDU1973 Prime Path BFS算法解析
本文详细解析了HDU1973 Prime Path问题的BFS算法实现过程,阐述了如何通过广度优先搜索找到两个四位质数间转换所需的最小成本,并附带了完整的代码示例。

hdu 1973 Prime Path (bfs)

Problem Description

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

 

#include<algorithm>

#include<cstdio>

#include<cstring>

#include<iostream>

#include<queue>

using namespace std;

int a,b;

 

bool sushu(int n)

{

    if(n==1)

        return false;

    if(n==2)

        return true;

    int i;

    for(i=2;i*i<=n;i++)

    {

        if(n%i==0)

            return false;

    }

    return true;

}

int mark[100005],num[100005];

void bfs()

{

    queue<int>q;

    q.push(a);

    num[a]=0;

    mark[a]=1;

    while(!q.empty())

    {

        int it=q.front();

        q.pop();

        if(it==b)

        {

            cout<<num[b]<<endl;

            return ;

        }

        int i;

        int ge,shi;

        ge=it%10;

        shi=(it/10)%10;

        for(i=1;i<=9;i+=2)

        {

            int y=(it/10)*10+i;//变个位

            if(y!=it&&!mark[y]&&sushu(y))//没出现过 是素数 不是输入的数

            {

                mark[y]=1;

                q.push(y);

                num[y]=num[it]+1;

            }

        }

        for(i=0;i<=9;i++)

        {

            int y=(it/100)*100+i*10+ge;//变十位

            if(y!=it&&!mark[y]&&sushu(y))//没出现过 是素数 不是输入的数

            {

                mark[y]=1;

                q.push(y);

                num[y]=num[it]+1;

            }

        }

        for(i=0;i<=9;i++)

        {

            int y=(it/1000)*1000+i*100+shi*10+ge;//变百位

            if(y!=it&&!mark[y]&&sushu(y))//没出现过 是素数 不是输入的数

            {

                mark[y]=1;

                q.push(y);

                num[y]=num[it]+1;

            }

        }

        for(i=1;i<=9;i++)

        {

            int y=it%1000+i*1000;//变千位

            if(y!=it&&!mark[y]&&sushu(y))//没出现过 是素数 不是输入的数

            {

                mark[y]=1;

                q.push(y);

                num[y]=num[it]+1;

            }

        }

    }

    cout<<"Impossible"<<endl;

}

int main()

{

    int T;

    cin>>T;

    while(T--)

    {

        cin>>a>>b;

        memset(mark,0,sizeof(mark));

        memset(num,0,sizeof(num));

        bfs();

    }

    return 0;

}





大神思路:题目大意就是给你两个四位数数ab然后a每次可以改变a的个位十位百位或者千位上的一个数字,求出最终得到数字b所需要的最短次数,当然每次改变数字得到的数字需要是一个质数,如果你无论如何都不能在要求每次变换都为质数的约束情况下把a转化为b那么输出Impossible否则求出最短的次数,所以这道题的简单思路就是分别搜索每一次改变的位数之后得到的新数字是不是质数且能不能等于这个目标b的值,如果得到的是质数则次数+1,直到最终得到想要的结果为止,统计累加的次数,然后就是分析怎么优化了,首先它说的是素数,所以应该先用一个BOOL函数来筛选出满足条件的素数,在筛选过程中记得将判定素数的那个循环的复杂度变成根号N以免增加电脑的计算量,筛选素数之后再用BFS进行搜索统计就可以了,依然是利用队列来做,当然对于细节的处理上就是要注意每一位的取值情况,个位必然是奇数,千位得从1开始,十位百位嘛改变时没有特殊要求,不过注意要记得先把十位和个位分离出来啊!

大神代码:

#include<iostream>

#include<queue>

#include<cstring>

using namespace std;

#define maxn 10000

bool is_prime[maxn];

bool vis[maxn];

int num[maxn];

int start,end;

int n;

void bfs(int x)

{

    queue<int>P;

    P.push(x);//a入队

    while(!P.empty())

    {

        int t=P.front();//出队

        if(t==end)//变成b

            return ;

        vis[t]=true;//标记

        P.pop();

        char ch[5];

        sprintf(ch,"%d",t);//t转化成字符串好处理

        for(int j=0;j<4;j++)//枚举换的四个位置

        {

            for(int k=0;k<10;k++)//每个位置枚举变换的值

            {

                int temp;

                if(j==0&&k==0)//不能将最高位换成0

                    continue;

                if(j==0)//换千位

                    temp=k*1000+(ch[1]-'0')*100+(ch[2]-'0')*10+(ch[3]-'0');

                else if(j==1)//换百位

                    temp=k*100+(ch[0]-'0')*1000+(ch[2]-'0')*10+(ch[3]-'0');

                else if(j==2)//换十位

                    temp=k*10+(ch[0]-'0')*1000+(ch[1]-'0')*100+(ch[3]-'0');

                else if(j==3)//换个位

                    temp=k+(ch[0]-'0')*1000+(ch[1]-'0')*100+(ch[2]-'0')*10;   

                if(is_prime[temp]&&!vis[temp]&&temp<10000)//是素数就换

                {

                    num[temp]=num[t]+1;//步数加一

                    vis[temp]=true;//标记该素数

                    P.push(temp);//将该素数进队

                }

            }

        }

    }

}

int main()

{

    for(int i=0;i<10000;i++)//打素数表

        is_prime[i]=true;

    is_prime[0]=is_prime[1]=false;

    for(int i=2;i<100;i++)

        if(is_prime[i])

            for(int j=2;i*j<10000;j++)

                is_prime[i*j]=false;

    cin>>n;

    while(n--)

    {

        cin>>start>>end;

        memset(vis,false,sizeof(vis));//初始化标记数组

        memset(num,0,sizeof(num));//初始化步数

        bfs(start);

        if(num[end]==0&&start!=end)//a不能变成b

            cout<<"impossible"<<endl;

        else//可以则输出最少变换数

            cout<<num[end]<<endl;

    }

    return 0;

}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值