kuangbin带你飞——专题一 简单搜索(6)
题目来源:POJ 3126 Prime Path
题解
题目要求,将一个四位数每次更改一个位置上的数字,并且要求改后的数字为素数,直到改完的数字为目标数字。
输出最短的费用。
经典BFS(广度优先搜索)
题型,用地图数组num
表示经过该点是所花费的费用,从起点入队,将分别更改四个位置的数字作为四个方向,向四个方向遍历,直到队空。
最后地图数组num
中存储的就是最少的花费。
题目重点
素数的判断,可使用欧拉筛
来进行判断。
// prime 记录素数
int prime[maxn];
// visit 判断素数,1 表示为素数,0 表示为合数
int visit[maxn];
// cnt 计数
int cnt = 0;
void Prime()
{
// 初始化数组
memset(visit, 1, sizeof(visit));
memset(prime, 0, sizeof(prime));
visit[1] = visit[0] = 0;
// 从 2 开始遍历
for (int i = 2; i <= maxn; i++)
{
if (visit[i])
prime[++cnt] = i; //纪录素数
for (int j = 1; j <= cnt && i * prime[j] <= maxn; j++)
// 原理:任意一个合数都能表示成两个素数的乘积
{
visit[i * prime[j]] = 0;
// 当 i 是 prime[j] 的倍数时,i = k * prime[j]
// 如果继续运算 j+1,i * prime[j+1] = prime[j] * k * prime[j+1]
// 这里 prime[j] 是最小的素因子
// 当 i = k * prime[j+1] 时会重复,所以才跳出循环
if (i % prime[j] == 0)
break;
}
}
}
AC代码
#include <iostream>
#include <cstring>
#include <queue>
#include <map>
using namespace std;
const int maxn = 1e4;
#define inf 0x3f3f3f3f
// 地图数组
int num[maxn];
// 欧拉筛
int prime[maxn];
bool visit[maxn];
void Prime()
{
memset(visit, 0, sizeof(visit));
memset(prime, 0, sizeof(prime));
visit[0] = visit[1] = 1;
for (int i = 2; i <= maxn; ++i)
{
if (!visit[i])
prime[++prime[0]] = i;
for (int j = 1; j <= prime[0] && i * prime[j] <= maxn; ++j)
{
visit[i * prime[j]] = 1;
if (i % prime[j] == 0)
break;
}
}
}
// 判断素数的函数
bool is_Prime(int n)
{
return !visit[n];
}
int m, n;
void bfs(int x, int y)
{
// 初始数组
memset(num, inf, sizeof(num));
num[x] = 0;
// pair 建队
queue<pair<int, int>> q;
// 起点入队
q.push(make_pair(x, 0));
while (!q.empty())
{
pair<int, int> p = q.front();
q.pop();
// 当到达终点时,继续循环,寻找最少花费
if (p.first == y)
continue;
// 向四个方向遍历
for (int i = 0; i <= 9; ++i)
{
int N = p.first, M = p.second;
int nn = (N / 10) * 10 + i;
if (num[nn] > M + 1 && is_Prime(nn))
{
q.push(make_pair(nn, M + 1));
num[nn] = M + 1;
}
nn = (N / 100) * 100 + i * 10 + N % 10;
if (num[nn] > M + 1 && is_Prime(nn))
{
q.push(make_pair(nn, M + 1));
num[nn] = M + 1;
}
nn = (N / 1000) * 1000 + i * 100 + N % 100;
if (num[nn] > M + 1 && is_Prime(nn))
{
q.push(make_pair(nn, M + 1));
num[nn] = M + 1;
}
// 防止出现前导 0
if (i != 0)
{
nn = i * 1000 + N % 1000;
if (num[nn] > M + 1 && is_Prime(nn))
{
q.push(make_pair(nn, M + 1));
num[nn] = M + 1;
}
}
}
}
}
int main()
{
// 初始化 visit 数组
Prime();
int t;
scanf("%d", &t);
while (t--)
{
scanf("%d%d", &m, &n);
bfs(m, n);
if (num[n] == 10000)
printf("Impossible\n");
else
printf("%d\n", num[n]);
}
return 0;
}