POJ 3126.Prime Path(筛法求素数表+bfs+剪枝)(c++)

POJ 3126.Prime Path(筛法求素数表+bfs+剪枝)

题目链接: POJ 3126.Prime Path
题目大意: 找到从素数A转换至素数B的最短方式(A,B都为四位数)
每次转换后的数字必须是四位素数,且每次只能改变四位数中的其中一位。(具体输入等问题请看原题
样例分析: 1033->1733->3733->3739->3779->8779->8179
测试数据:

Sample Input
3
1033 8179
1373 8017
1033 1033
Sample Output
6
7
0

题解思路: 首先英文要判断是否是素数,而且数据还挺大的,所以我们肯定会想到用埃拉托斯特尼筛法(筛法求素数)来求出10000以内的素数表,然后就可以开始用bfs来求解问题了。首先找到bfs每一步的所有去向,根据题目,就是把4个位上的数换成其他的数字,而且还要保证是素数,那么就是列举所有可能的数的替换情况,判断是否是素数然后入队
解决替换数字的问题成为解题关键,我选择分别枚举替换的位数,和替换后的数字然后返回替换后的数值。
这里有两种方法,一是:直接进行数的拆分和合并,(分离出各个位数)二是:运用字符数组然后替换,再转成数值大小。我给出的代码用的是第一种方法。
关于剪枝: 排除以下几种情况:1.第一位不是0 2.最后一位数不是0和2的倍数(偶数不是素数) 3.最后一位不是5和0(不是5的倍数)

最后来看代码:
这里有一个小细节,在我写代码的时候困扰了我很久,因为我并没有排除替换某一位的数为自己,即是替换前后的数值一模一样,但是这一步还是记录了步数,就是最开始输入的数没有变化vis变成了1而不是0,这样就会导致后面的每一步都会多加1。所以后面输出的时候就是x-1。

#include<iostream>
#include<vector>
#include<queue>
#include<cstring>
using namespace std;
vector<int> p(10000, 1);
queue<int> q;
int n;
int vis[10000];                       \\记录步数和判断是否被访问过
void getperm() {                      \\筛法求素数表
	for (int i = 2; i < 10000; i++) {
		if (p[i] == 1) {
			for (int j = 2 * i; j < 10000; j+=i) {
				p[j] = 0;
			}
		}
	}
}
int change(int b, int n, int c)      \\数字替换函数
{
	switch (n)
	{
	case 0:	return b % 1000 + c * 1000;
	case 1:	return b / 1000 * 1000 + b % 100 + c * 100;
	case 2:	return b / 100 * 100 + b % 10 + c * 10;
	case 3: return b / 10 * 10 + c;
	}
}
int bfs(int begin,int end)
{
	memset(vis, 0, sizeof(vis)); 
	int next, start;
	start = begin;
	vis[start] = 1;
	q.push(start);
	while (!q.empty()) {
		start = q.front();
		q.pop();
		if (start == end) {
			return vis[start];
		}
		else {
			for (int i = 0; i < 4; i++) {
				for (int j = 0; j <= 9; j++) {
					if ((i != 0 || j != 0) && (i != 3 || j % 2 != 0 || j!=5)) {
						next = change(start, i, j);
						if (p[next] == 1 && !vis[next]) {
							vis[next] = vis[start] + 1;
							q.push(next);
						}
					}
				}
			}
		}
	}
	return -1;
}
int main()
{
	int begin, end;
	getperm();
	cin >> n;
	while (n--) {
		cin >> begin >> end;
		int x = bfs(begin, end);
		if (x >= 0) {
			cout << x - 1<< endl;
		}
		else {
			cout << "Impossible" << endl;
		}
		while (!q.empty()) {
			q.pop();
		}
	}
	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值