POJ 3126 Prime Path【BFS】
<题目链接>
题目大意:
给你两个四位数,它们均为素数,以第一个四位数作为起点,每次能够变换该四位数的任意一位,变换后的四位数也必须是素数,问你是否能够通过变换使得第一个四位数变成第二个四位数。
解题分析:
先打一张素数表,然后进行BFS搜索,对于每次搜索的当前数,枚举某一位与它不同的所有数,判断它是否符合条件,如果符合,就将它加入队列,继续搜索。
#include<stdio.h> #include<string.h> #include<iostream> #include<queue> #include<math.h> #define min 0x3f3f3f3f using namespace std; int arr[10005]; int vis[10005]; int n,m; void prim() //素数打表 { int i,j; arr[0]=arr[1]=1; for(i=2;i<=10000;i++) { if(!arr[i]) { for(j=i*2;j<=10000;j+=i) arr[j]=1; } } } int bfs(int first,int last) { queue <int>q; int v,i,j,temp,vtemp,count[10005],N[4]; memset(vis,0,sizeof(vis)); memset(count,0,sizeof(count)); q.push(first); vis[first]=1; while(!q.empty()) { v=q.front(); q.pop(); N[0]=v/1000; N[1]=v%1000/100; N[2]=v%100/10; N[3]=v%10; //N[]为v的各位数 for(j=0;j<4;j++) { temp=N[j]; for(i=0;i<10;i++) if(i!=temp) //枚举某一位与当前数不同的数 { N[j]=i; vtemp=N[0]*1000+N[1]*100+N[2]*10+N[3]; if(!vis[vtemp] && !arr[vtemp] && vtemp>1000) //如果枚举的这个数没有枚举过,并且是一个四位数素数 { vis[vtemp]=1; //已经走过的就标记 count[vtemp]=count[v]+1; //步数加一 q.push(vtemp); } if(vtemp==last) return count[vtemp]; //找到了最终的数 } N[j]=temp; //将原来的数还原,防止对下一步造成影响 } if(v==last) return count[v]; //找到了最终的数 } return -1; } int main() { int t,k; cin>>t; prim(); while(t--) { cin>>n>>m; k=bfs(n,m); if(k!=-1) cout<<k<<endl; else cout<<"Impossible"<<endl; } return 0; }
下面是另一份代码,与上面枚举当前四位数的每一位数不同的是,这里用的是链式前向星储存某一个四位数能够转化成的所有下一个四位数。但是不知道为什么这份代码WA了。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#include <cstdio> #include <cstring> #include <cmath> #include <iostream> #include <algorithm> #include <queue> using namespace std; const int maxn=10000+100; int isprime[maxn+1000]; int prime[maxn]; int top; int n,m,ans; void getprime(){ top=0; memset(isprime,0,sizeof(isprime)); for(int i=2;i<=sqrt(maxn*1.0);i++){ if(!isprime[i]){ for(int j=i*i;j<=maxn;j+=i){ isprime[j]=1; } } } for(int i=1000;i<=9999;i++){ //打表找出四位数的素数 if(!isprime[i]){ prime[++top]=i; } } } const int N=1100; struct EDGE{ //用链式前向星记录与当前点只有一位不同的素数,即记录当前数下一步能够转化成的数 int to; int next; }edge[N*N]; //因为我打了一下表,发现top的值接近1100,所以这里这样设数组的上界 int head[11000]; int cnt; struct node{ int loc; int step; node(int a=0,int b=0):loc(a),step(b){} }; int vis[11000]; bool juge(int a,int b){ //判断这两个数是否只有某一位数不同 int fp=0; while(a){ int a1=a%10; int a2=b%10; a/=10; b/=10; if(a1==a2)fp++; } if(fp==3)return true; return false; } void init(){ memset(head,-1,sizeof(head)); cnt=0; } void add(int u,int v){ edge[cnt].to=v; edge[cnt].next=head[u]; head[u]=cnt++; } bool bfs(){ memset(vis,0,sizeof(vis)); queue<node>q; q.push(node(n,0)); while(!q.empty()){ node now=q.front(); q.pop(); if(now.loc==m){ //找到了最终要找的数 ans=now.step; return true; } if(vis[now.loc])continue; vis[now.loc]=1; for(int i=head[now.loc];i!=-1;i=edge[i].next){ //枚举下一步所有满足条件的数(已经预处理过了) int v=edge[i].to; if(vis[v])continue; q.push(node(v,now.step+1)); } } return false; } int main(){ getprime(); int t;scanf("%d",&t); while(t--){ init(); int a,b; scanf("%d %d",&a,&b); for(int i=1;i<=top;i++){ if(prime[i]==a)n=i; if(prime[i]==b)m=i; } for(int i=n;i<=m;i++){ for(int j=n;j<=m;j++){ if(juge(prime[i],prime[j])){ //预处理,找到当前数下一步能够转化的所有数 add(i,j); } } } if(bfs()){ printf("%d\n",ans); } else printf("Impossible\n"); } return 0; }
2018-08-30
作者:is_ok
出处:http://www.cnblogs.com/00isok/
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。