参考博客https://www.xuebuyuan.com/2962927.html
27号 28号出去爬山了手头也不好带电脑= =,所以咕咕了两天(绝不是懒着不想写),今天把欠的题目补上。
poj 3126 题目大意 四位数从一个素数到另一个素数,通过1位1位的变动(变动一位距离加1),中间还只能走素数,请问最短距离?
其实很明显用BFS的思路去做,只不过给我们加了限定条件(只能是素数),而且是4位每一位都有10种路可以走。我一开始做这道题的时候就想这样的话每一个数有40条路可以走= =,emm感觉好大,但是好像对于这个确实没有什么好的优化方法,也只能硬着头皮去写,如果有什么别的好方法欢迎在评论中写出。
另外对于此题还是一个学习素数筛的好例题
附https://blog.csdn.net/qq_41117236/article/details/81152055,这是我学习素数筛时看的博客,分类很详细,本代码中我还是采用了爱拉托斯尼特筛法(毕竟好写好理解= =) 复杂度是O(N*lnlnN)
底下两种算法是在批量检测一堆数是不是素数时的好总结,第一种就是判断单个数是不是素数的标准写法,做个模板用吧。
ac代码
#include<cstdio> #include<iostream> #include<cmath> #include<cstring> #include<set> #include<queue> using namespace std; int num,aim; struct node { int num,step; }node_num,node_aim; //step是所需距离 const int maxn=1e5; bool number[maxn+5]; void isprime(int N) { int i,j; memset(number,true,sizeof(number)); for(i=2;i<=sqrt(N*1.0);i++) { if(number[i]==true) { for(j=i*i;j<=N;j+=i) { number[j]=false; } //二次筛选法:i是素数,则下一个起点是i*i,把后面的所有的i*i+2*n*i筛掉 } } } int bfs() { queue<node>q; q.push(node_num); set<int>s; s.insert(node_num.num); while(!q.empty()) { node shu = q.front(); q.pop(); for(int i = 0; i < 4; i ++) //一共4位每一位都要进行9次变换(因为都让这位变为0) { int P = (int)pow(10.0,i); int digt = (shu.num/P)%10; int temp = shu.num - digt*P; //这三步是为了让我们要操作的那一位变为0 for(int j = 0; j < 10; j ++) { if(i == 3 && j == 0) continue; //首尾不能为0 int flag = temp+P*j; if(number[flag]==true && s.find(flag) == s.end()) //set.find()函数功能是在set中遍历如果没查到就返回set.end,以此来实现查重功能 { node N; N.num = flag; N.step = shu.step+1; if(flag == aim) return N.step; q.push(N); s.insert(flag); } } } } return 0; } int main() { int t; cin>>t; while(t--) { cin>>num>>aim; isprime(9999); node_num.num = num; node_num.step = 0; cout<<bfs()<<endl; } return 0; }
另外因为此题范围较小,可以把范围内的素数全部打表,但是那样还是要对每个素数判断是否只是相差一位来看能不能走(BFS限定条件),这样岂不是每一步可走的路更多了,本菜鸟还不太明白那样复杂度会降低吗,欢迎大家评论教我或者对本代码进行指正。
(其实是27日的题- -,day5)