POJ 3126 Prime Path(bfs)

- POJ 3126 -

Prime Path

Time Limit: 1000MS | Memory Limit: 65536K

题意:

给定一个数据 t ,表示测试案例组数;
接下来 t 行,每行2个四位数 a、b,求把 a 变成 b 最少需要多少步,若不能按要求由 a 得到 b ,则输出“Impossible”;
条件:每次只能改变一位数字,且每次改变后的数必须是素数。

数据范围:

t <= 100

解题思路:

宽度优先搜索

先用素数筛法得到 1000~9999 的所有素数并存入数组,然后每次由前一个素数求改变一位数后的下一个素数时,依次判断这些素数里面有没有符合条件的素数,若有则把它入队并记录得到这个素数所需变换的次数,直到得到素数 b 为止,若队列为空仍然没有找到,则说明不能按要求由 a 得到 b ,输出“Impossible”。

代码:

#include <iostream>
#include <cstdio>
#include <cstring>
#include <string>
#include <algorithm>
#include <cmath>
#include <stack>
#include <queue>
#include <vector>
#include <map>
using namespace std;
#define INF 0x3f3f3f
#define zero 1e-7

typedef long long ll;
const int N=1e4;
int prime[N], cnt;//prime数组存储1000~9999范围内的素数,cnt记录该范围内素数个数
int st[N];//记录得到素数i需要改变的次数
bool vis[N];//标记是否为素数
queue<int> q;

void getPrime() {
    memset(vis, false, sizeof(vis));
    vis[1]=true; cnt=0;
    for(int i=2; i<N; i++) {//素数筛法
        if(!vis[i]) {
            for(int j=i*2; j<N; j+=i)
                vis[j]=true;
        }
    }
    for(int i=1000; i<=9999; i++) {
        if(!vis[i])
            prime[cnt++]=i;
    }
    return ;
}

bool judge(int a, int b) {//判断素数b是否符合条件
    int num=0;
    while(a && b) {
        if(a%10 != b%10) num++;
        a/=10; b/=10;
    }
    if(num==1) return true;
    else return false;
}

void bfs(int from, int to) {//宽度优先搜素
    while(!q.empty()) {
        int top=q.front();
        q.pop();
        if(top==to) {
            printf("%d\n", st[to]);
            return ;
        }
        for(int i=0; i<cnt; i++) {
            if(st[prime[i]]==0 && judge(top, prime[i])) {
                q.push(prime[i]);
                st[prime[i]]=st[top]+1;//得到prime[i]经过的步骤为得到top的步骤数+1
                //printf("prime[%d]=%d, ", i, prime[i]);
            }
        }
    }
    printf("Impossible\n");
    return ;
}

int main() {
    int n, a, b;
    getPrime();
    scanf("%d", &n);
    while(n--) {
        memset(st, 0, sizeof(st));
        while(!q.empty()) q.pop();//把队列清零
        scanf("%d %d", &a, &b);
        q.push(a);
        bfs(a, b);
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值