POJ3126 Prime Path(BFS+线性筛/埃氏筛)

题目传送门

这道题给出了两种做法:

首先当然要请出我们可爱的线性筛:

int primes[N], cnt;     // primes[]存储所有素数
bool st[N];         // st[x]存储x是否被筛掉

void get_primes(int n)
{
    for (int i = 2; i <= n; i ++ )
    {
        if (!st[i]) primes[cnt ++ ] = i;
        for (int j = 0; primes[j] <= n / i; j ++ )
        {
            st[primes[j] * i] = true;
            if (i % primes[j] == 0) break;
        }
    }
}


/*作者:yxc
链接:https://www.acwing.com/blog/content/406/
来源:AcWing
*/

1.按位BFS素数
这个思路比较基础,就是利用了BFS的“最短性质",推出来的:
枚举每一位,将每一位改成其他数,然后把它送入队列当中去,每一次BFS的过程中,都将它和标准数据做一个对比,如果是一致的那么就结束,并输出,如果最后队列空了,还没有找到,那么就输出”impossble"。
思路比较简单,下面看ac代码:

#include<iostream>
#include<cstring>
#include<queue>
#define N 10000
using namespace std;
int primes[N], cnt;     
bool st[N];  
int num[12100];
bool stt[10000];
queue<int>q;
void get_primes(int n)
{
    for (int i = 2; i <= n; i ++ )
    {
        if (!st[i]) primes[cnt ++ ] = i;
        for (int j = 0; primes[j] <= n / i; j ++ )
        {
            st[primes[j] * i] = true;
            if (i % primes[j] == 0) break;
        }
       
    }
}

int main(){
	int T;
	cin>>T;
	get_primes(10000);
	///cout<<
	while(T--){
		while(q.size()){
			q.pop();
		}
		int a,b;
		cin>>a>>b;
		if(a==b){
			cout<<"0"<<endl;
			continue;
		}
		memset(num,0,sizeof num);
		memset(stt,0,sizeof stt);
		q.push(a);
		stt[a]=true;
		int u=0;
		while(q.size()){
			int aa=q.front();
			q.pop();
			//cout<<aa<<endl;
			for(int i=1;i<=9;i++){
				int bb=i*1000+aa%1000;
				if(bb==b){
					u=1;
					cout<<num[aa]+1<<endl;
					break;
				}
				if(!st[bb]&&!stt[bb]){
					stt[bb]=true;
					num[bb]=num[aa]+1;
					q.push(bb);	
				}
			}
			if(u)break;
			for(int i=0;i<=9;i++){
				int bb=(aa/1000)*1000+i*100+aa%100;
				if(bb==b){
					u=1;
					cout<<num[aa]+1<<endl;
					break;
				}
				if(!st[bb]&&!stt[bb]){
					stt[bb]=true;
					num[bb]=num[aa]+1;
					q.push(bb);	
				}
			}
			if(u)break;
			for(int i=0;i<=9;i++){
				int bb=(aa/100)*100+i*10+aa%10;
				if(bb==b){
					u=1;
					cout<<num[aa]+1<<endl;
					break;
				}
				if(!st[bb]&&!stt[bb]){
					stt[bb]=true;
					num[bb]=num[aa]+1;
					q.push(bb);	
				}
			}
			if(u)break;
			for(int i=0;i<=9;i++){
				int bb=(aa/10)*10+i;
				if(bb==b){
					u=1;
					cout<<num[aa]+1<<endl;
					break;
				}
				if(!st[bb]&&!stt[bb]){
					stt[bb]=true;
					num[bb]=num[aa]+1;
					q.push(bb);	
				}
			}
			if(u)break;
		}
		if(u==0){
			cout<<"Impossible"<<endl;
		}
	}
	return 0;
}

2.按照素数进行BFS

思路较为相同,但是思考顺序发生了改变:
每一次进行搜索,找到所有和这个数只差一位的素数,让它们入队,最后返回的是我们这个数的结果。

#include <iostream>
#include <cstring>
#include <cmath>
#include <string>
#include <algorithm>
#include <queue>
#include <utility>
#define me memset 

using namespace std;

typedef long long ll;

const int N = 10010;
const int null = 0x3f3f3f3f;

int T,a,b;
int d[N];
int primes[N],cnt;
bool st[N];

void get_primes()
{
    for (int i = 2; i <= 10000; i ++ )
    {
        if (st[i]) continue;
        primes[cnt ++ ] = i;
        for (int j = i + i; j <= 10000; j += i)
            st[j] = true;
    }
}

bool check(int x,int y)
{
	int usa = 0;
	while(x && y)
	{
		int i = x % 10,j = y % 10;
		
		if(i != j) usa ++;
		
		x /= 10;
		y /= 10;
	}
//	cout << usa << endl;
	
	if(usa == 1) return true;
	else return false;
}

int bfs()
{
	queue<int> q;
	me(d,-1,sizeof d);
	
	q.push(a);
	d[a] = 0;
	
	while(q.size())
	{
		int t = q.front();
		q.pop();
		
		for(int i = 168;i < cnt ;i ++)
		{
			if(check(primes[i],t) && d[primes[i]] == -1)
			{
				q.push(primes[i]);
				d[primes[i]] = d[t] + 1;
			}
		}
	}

	
	return d[b];
}

int main()
{
	cin >> T;
	
	get_primes();
	
//	for(int i = 0;i < cnt;i ++) cout << primes[i] << endl;
	
//	cout << cnt << endl;
	
//	cout << primes[168] << endl;
	
	while(T --)
	{
		cin >> a >> b;
		
		if(a == b)
		{
			cout << "0" << endl;
			continue;
		}
		
	
		
	//	check(a,b);
		
		if(bfs()) cout << d[b] << endl;
		else cout << "Impossible" << endl;
		
		
	}
	
	return 0;
}
上一篇:java replace选择规则替换


下一篇:最走心的网络知识科普帖