当前位置: 代码迷 >> 综合 >> POJ 3126 Prime Path (换门牌)
  详细解决方案

POJ 3126 Prime Path (换门牌)

热度:52   发布时间:2023-12-08 11:25:06.0

题目链接:POJ 3126

题意:

给出两个数a,b,且a,b均为四位素数,a<b。每次只改变a的一位数字,且改变后的数字仍是四位素数(也就是千位不能变为0),经过若干次操作使得最终从a变为b,问最少经历多少次操作?

思路:

先对四位正整数素数打表,然后用BFS搜索,每次从队列首去除一个元素,判断是否是目标数,否则将由这个数产生的符合条件的数字入队列(先判断是否是目标数)。开两个数组,一个用于记录当前数字是否访问过,一个用于记录到达当前数字的步骤数。


#include <iostream>
#include <queue>
#include <algorithm>
#include <cstdio>
#include <cstring>
#include <sstream>
using namespace std;
const int maxn = 10000;
int IsPrime[maxn],vis[maxn],cnt[maxn];
int n, a, b, ans;int isprime(int n)
{//判断n是否为素数for (int i = 2;i*i <= n;i++)if (n%i == 0) return 0;return 1;
}void init()
{//对[1000,9999]的正整数进行素数打表for (int i = 1000;i < maxn;i++)IsPrime[i] = isprime(i);
}int BFS(int first,int last)
{memset(vis, 0, sizeof(vis));//vis[i]=0表示i尚未访问过memset(cnt, 0, sizeof(cnt));//cnt[i]表示到达i经历的步骤数queue<int> q;int v, temp, vtemp, digit[4];q.push(first);//将起始数入队列vis[first] = 1;//起始数访问过了while (!q.empty())//队列非空时{v = q.front();//取队首元素q.pop();//队首元素出队列if (v == last) return cnt[v];//队首元素==目标值,返回次数digit[0] = v / 1000;//千位digit[1] = v / 100 % 10;//百位digit[2] = v / 10 % 10;//十位digit[3] = v % 10;//个位for (int i = 0;i < 4;i++){//对每个数需要改变个十百千每个位上的数字temp = digit[i];for (int j = 0;j < 10;j++){//每个位上的数字从0到9开始替换if (temp != j){//数字不重合digit[i] = j;//这样做方便了计算vtemp!vtemp = digit[0] * 1000 + digit[1] * 100 + digit[2] * 10 + digit[3];if (vtemp > 999 && !vis[vtemp] && IsPrime[vtemp]){//千位不为0&&尚未访问过&&是素数cnt[vtemp] = cnt[v] + 1;//到达vtemp的步骤数=到达v的步骤数+1vis[vtemp] = 1;//标记访问过q.push(vtemp);//入队列}if (vtemp == last) return cnt[vtemp];}}digit[i] = temp;//别忘记替换回来!}}return -1;
}int main()
{
#ifdef LOCALfreopen("in.txt", "r", stdin);freopen("out.txt", "w", stdout);
#endifinit();while (~scanf("%d", &n)){while (n--){scanf("%d%d", &a, &b);ans = BFS(a,b);if (ans == -1) printf("Impossible\n");else cout << ans << endl;}}return 0;
}


  相关解决方案