(水)POJ-3126 BFS,埃式筛选及黑科技

题目大意:给定两个四位素数a  b,要求把a变换到b,变换的过程要保证  每次变换出来的数都是一个 四位素数,而且当前这步的变换所得的素数    前一步得到的素数  只能有一个位不同,而且每步得到的素数都不能重复。

题目链接:点击打开链接

分析:分析可知这题肯定是用搜索,每次改变某位,每位有0-9(首位无0)10种变法,一共40个方向,可是到底DFS还是BFS还是二分呢?可只二分对这题显然是不太好写的,DFS的话复杂度为O(40^n)估计几年也出不了结果来,,,然后BFS的话O(40*n)肯定是可以过的。BFS是很好写,麻烦的就在数字的转变和素数的判断。这里素数的判断由于是多组数据我们可以用埃式筛选打一个表(怎么实现可以直接看代码,自己思考下就行了,这里朴素的方法也是可以过的)。对于改变一个数字的某一位我们可以用到sprintf和sscanf这2个黑科技来简单的实现,只要先把初始数字v用sprintf打印到字符串里,然后利用字符串的随机访问来改变其中某一位就行了,接下来再用sscanf再输出到v中即可。

附上代码:

#include<iostream>
#include<queue>
#include<cstring>
using namespace std;
#define Max 10000+5
bool vis[Max], is_prime[Max];
int d[Max];
int T, a, b;
void get_prime()    //打素数表
{
	memset(is_prime, true, sizeof is_prime);
	for (int i = 2; i*i < Max; i++)
		if (is_prime[i])
			for (int j = 2 * i; j < Max; j += i)
				is_prime[j] = false;
	return;
}
int judge(int v,int i,int j)
{
	if (!is_prime[v]) return 0;   //不是素数返回0
	if (i == 1 && j == 0) return 0;  //首位为0返回0
	char s[6] = "\0";
	sprintf(s, "%d", v);
	s[i - 1] = j + '0';   //将第i位改成j
	sscanf(s, "%d", &v);
	if (!vis[v]) return v;   //返回改变后的值
	return 0;
}
int bfs()
{
	queue<int> q; 
	q.push(a);
	vis[a] = 1;
	while (!q.empty())
	{
		int v = q.front();
		q.pop();
		for (int i = 1; i <= 4; i++)   //枚举40个入口,分别为第i位改成j
			for (int j = 0; j <= 9; j++)
			{
				int t = judge(v, i, j);
				if (t)
				{
					vis[t] = 1;
					d[t] = d[v] + 1;
					q.push(t);
					if (t == b) return d[t];
				}
			}
	}
	return -1;
}
int main()
{
	scanf("%d", &T);
	get_prime();
	while (T--)
	{
		memset(vis, false, sizeof vis);
		memset(d, false, sizeof d);
		scanf("%d%d", &a, &b);
		if (a == b) printf("0\n");
		else
		{
			int ans = bfs();
			if (ans == -1) printf("Impossible\n");
			else printf("%d\n", ans);
		}
	}
	return 0;
}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值