POJ3126 Prime Path - 素数筛 - 宽度优先搜索(bfs)

Prime Path

 
 

题目大概意思:

给出两个素数 a a b b 1 0 3 < a , b < 1 0 4 10^3<a,b<10^4 ),每次可以修改 a a 的四位十进制数字中的一位数字,使其变为另外一个四位数的素数,问最少需要修改几次可以把 a a 变为 b b . 若不可能则输出 “ I m p o s s i b l e Impossible ”.

 
 

分析:

首先用埃式素数筛 O ( n log log n ) O(n·\log\log{n}) 的时间复杂度内,或线性素数筛 O ( n ) O(n) 的时间复杂度内筛选出所有的四位的素数,这样可以得到 1061 1061 个素数。

然后对这些素数两两判断,如果可以通过修改一位互相转换,则连一条双向边。这一步时间复杂度为 O ( n 2 lg a m a x ) O(n^2·\lg{a_{max}}) .

最后进行宽度优先搜索,计算 a a b b 的最短路径长度,每次宽度优先搜索的时间复杂度为 O ( E ) O(E) .

 
 
下面贴代码:

#include <cstring>
#include <cstdio>
#include <vector>
#include <queue>
using namespace std;

const int MAX_N = 10001;

struct P
{
	int d;
	int num;
	P(const int& d = 0, const int& num = 0)
		:d(d), num(num) {}
};

bool is_prime[MAX_N];
int primes[1062], pcnt;
vector<int> G[MAX_N];
bool used[MAX_N];

void init();
void getprime(const int N);
void add_edge(const int u, const int v);
int bfs(const int S, const int T);

int main()
{
	init();

	int T, a, b;
	scanf("%d", &T);

	while (T--)
	{
		scanf("%d%d", &a, &b);
		int ans = bfs(a, b);
		if (~ans)
		{
			printf("%d\n", ans);
		}
		else
		{
			printf("Impossible\n");
		}
	}

	return 0;
}

void add_edge(const int u, const int v)
{
	G[u].push_back(v);
	G[v].push_back(u);
}

int bfs(const int S, const int T)
{
	memset(used + 1000, false, sizeof(used) - 1000);

	queue<P> q;
	used[S] = true;
	q.push(P(0, S));

	while (!q.empty())
	{
		P cur = q.front();
		q.pop();
		if (cur.num == T) return cur.d;

		const vector<int>& v = G[cur.num];
		P nxt(cur.d + 1);

		for (int i = 0; i < v.size(); ++i)
		{
			nxt.num = v[i];
			if (!used[nxt.num])
			{
				used[nxt.num] = true;
				q.push(nxt);
			}
		}
	}
	return -1;
}

void init()
{
	getprime(MAX_N);
	memset(is_prime, false, 1000 * sizeof(bool));

	for (int i = 1; i < pcnt; ++i)
	{
		const int& ci = primes[i];
		for (int j = 0; j < i; ++j)
		{
			int pi = ci;
			int pj = primes[j];

			int unsame = 0;
			for (int k = 0; k < 4; ++k)
			{
				if (pi % 10 != pj % 10)
				{
					++unsame;
				}
				pi /= 10;
				pj /= 10;
			}
			if (unsame <= 1)
			{
				add_edge(ci, primes[j]);
			}
		}
	}
}

void getprime(const int N)
{
	memset(is_prime + 2, true, N - 2);
	for (int i = 2; i < N; ++i)
	{
		if (is_prime[i])
		{
			if (i > 1000) primes[pcnt++] = i;
			for (int j = i << 1; j < N; j += i)
			{
				is_prime[j] = false;
			}
		}
	}
}

原创文章 42 获赞 22 访问量 3049

猜你喜欢

转载自blog.csdn.net/weixin_44327262/article/details/97761431