POJ 3126 Prime Path 解题报告(BFS & 双向BFS)
来源:互联网 发布:java合成多张图片 编辑:程序博客网 时间:2024/05/21 07:53
题目大意:给定一个4位素数,一个目标4位素数。每次变换一位,保证变换后依然是素数,求变换到目标素数的最小步数。
解题报告:直接用最短路。
枚举1000-10000所有素数,如果素数A交换一位可以得到素数B,则在AB间加入一条长度为1的双向边。
则题中所求的便是从起点到终点的最短路。使用Dijkstra或SPFA皆可。
当然,纯粹的BFS也是可以的。
用Dijkstra算法A了题目之后,看了一下Discuss,发现了一个新名词,双向BFS。
即从起点和终点同时进行BFS,相遇则求得最短路。
借鉴了思想,自己动手实现了代码。原本以为双向比单向快一倍而已,其实远远不止。
笔者用30W数据分别测试了单向和双向。环境为CodeBlock+MinGW4.7,Debug,双向时间为8.618s,而单向为惊人的139.989s!
简单思考了一下,也还是合理的。单向每次的增长是指数级的,而双向的指数只有单向的一半,优化程度相当高。
好了,贴代码~首先是双向BFS的Dijkstra:
#include <cstdio>#include <cstring>#include <queue>using namespace std;const int maxn=10010;int prime[maxn];const int maxV=1100;int first[maxV],vv[maxV*maxV],nxt[maxV*maxV];int num[maxV];bool vis[2][maxV];int index;bool check(int a,int b){ int k=a-b; if(k%1000==0) return true; if(k<1000 && k%100==0 && a/1000==b/1000) return true; if(k<100 && k%10==0 && a/100==b/100) return true; if(a/10==b/10) return true; return false;}void calPrime(){ for(int i=2;i<maxn;i++) if(!prime[i]) { for(int j=2*i;j<maxn;j+=i) prime[j]=true; if(i>=1000 && i<10000) { num[++index]=i; prime[i]=index; } } int e=2; memset(first,0,sizeof(first)); for(int i=1;i<=index;i++) for(int j=i+1;j<=index;j++) if(check(num[j],num[i])) { nxt[e]=first[i],vv[e]=j,first[i]=e++; nxt[e]=first[j],vv[e]=i,first[j]=e++; }}struct Node{ int node; int level; bool operator<(const Node& cmp) const { return level>cmp.level; }} p,q;int Dijkstra(int sta,int end){ if(sta==end) return 0; memset(vis,0,sizeof(vis)); sta=prime[sta]; end=prime[end]; priority_queue<Node> pq[2]; p.node=sta; p.level=0; vis[0][p.node]=true; pq[0].push(p); p.node=end; p.level=0; vis[1][p.node]=true; pq[1].push(p); for(int i=0; !pq[0].empty() && !pq[1].empty() ;i++) { int sel=0; if(pq[0].size()>pq[1].size()) sel++; int level=pq[sel].top().level; while(!pq[sel].empty()) { p=pq[sel].top(); if(p.level!=level) //先判断,否则会pop掉丢失情况 break; pq[sel].pop(); for(int e=first[p.node];e;e=nxt[e]) { if(vis[1-sel][vv[e]]) return i+1; if(!vis[sel][vv[e]]) { q.level=p.level+1; q.node=vv[e]; vis[sel][vv[e]]=true; pq[sel].push(q); } } } } return -1;}int main(){ calPrime(); int T; scanf("%d",&T); while(T--) { int sta,end; scanf("%d%d",&sta,&end); int ans=Dijkstra(sta,end); if(ans==-1) printf("Impossible\n"); else printf("%d\n",ans); }}
然后是单向的BFS+Dijkstra:
#include <cstdio>#include <cstring>#include <queue>using namespace std;const int maxn=10010;int prime[maxn];const int maxV=1100;int first[maxV],vv[maxV*maxV],nxt[maxV*maxV];int num[maxV];bool vis[maxV];int index;int count;bool check(int a,int b){ int k=a-b; if(k%1000==0) return true; if(k<1000 && k%100==0 && a/1000==b/1000) return true; if(k<100 && k%10==0 && a/100==b/100) return true; if(a/10==b/10) return true; return false;}void calPrime(){ for(int i=2;i<maxn;i++) if(!prime[i]) { for(int j=2*i;j<maxn;j+=i) prime[j]=true; if(i>=1000 && i<10000) { num[++index]=i; prime[i]=index; } } int e=2; memset(first,0,sizeof(first)); for(int i=1;i<=index;i++) for(int j=i+1;j<=index;j++) if(check(num[j],num[i])) { nxt[e]=first[i],vv[e]=j,first[i]=e++; nxt[e]=first[j],vv[e]=i,first[j]=e++; }}struct Node{ int k; int w; bool operator<(const Node& cmp) const { return w>cmp.w; }} p,q;int Dijkstra(int sta,int end){ memset(vis,0,sizeof(vis)); end=prime[end]; p.k=prime[sta]; p.w=0; vis[p.k]=true; priority_queue<Node> pq; pq.push(p); while(!pq.empty()) { p=pq.top(); pq.pop(); if(p.k==end) return p.w; for(int e=first[p.k];e;e=nxt[e]) if(!vis[vv[e]]) { q.k=vv[e]; q.w=p.w+1; vis[q.k]=true; pq.push(q); } } return -1;}int main(){ calPrime(); int T; scanf("%d",&T); while(T--) { int sta,end; scanf("%d%d",&sta,&end); int ans=Dijkstra(sta,end); if(ans==-1) printf("Impossible\n"); else printf("%d\n",ans); }}
另一版本代码:
#include <cstdio>#include <cstring>#include <algorithm>using namespace std;bool prime[10000];void calPrime(){ for(int i=2;i<10000;i++) if(!prime[i]) for(int j=i+i;j<10000;j+=i) prime[j]=true; for(int i=2;i<1000;i++) prime[i]=true;}int ten[] = {1, 10, 100, 1000, 10000};bool vis[10000];int stack[10000][2];int top[2];void work(){ int a, b; scanf("%d%d", &a, &b); int now=1,pre=0; memset(vis, 0, sizeof(vis)); top[now]=0; stack[top[now]++][now]=a; vis[a]=true; for(int t=0;;t++) { swap(now, pre); top[now]=0; if(top[pre]==0) return ; for(int j=0;j<top[pre];j++) { int num=stack[j][pre]; if(num==b) { printf("%d\n", t); return; } for(int i=0;i<4;i++) { int newNum = num-(num%ten[i+1]-num%ten[i]); for(int k=0;k<10;k++,newNum+=ten[i]) if(!prime[newNum] && !vis[newNum]) stack[top[now]++][now]=newNum, vis[newNum]=true; } } }}int main(){ calPrime(); int T; scanf("%d", &T); while(T--) work();}
- POJ 3126 Prime Path 解题报告(BFS & 双向BFS)
- poj poj 3126 Prime Path(BFS)
- poj 3126 Prime Path(bfs搜索)
- POJ 3126 Prime Path (BFS)
- poj 3126 Prime Path(BFS)
- poj 3126 Prime Path (bfs)
- POJ 3126 Prime Path(BFS算法)
- Prime Path (poj 3126 bfs)
- POJ 3126 Prime Path(BFS)
- POJ 3126 - Prime Path(BFS)
- poj 3126 Prime Path(BFS)
- POJ 3126 Prime Path(BFS)
- POJ 3126 Prime Path (bfs、埃氏筛法)
- POJ 3126 Prime Path (BFS)
- POJ 3126 Prime Path(bfs)
- POJ 3126 Prime Path (BFS)
- POJ 3126 Prime Path (BFS)
- POJ 3126 Prime Path (BFS)
- C# 汉字转拼音与汉字简繁转换
- mysql备份与恢复
- Mac Eclipse SVN 安装
- jQuery 基本语法
- hdu1372 Knight Moves (BFS)
- POJ 3126 Prime Path 解题报告(BFS & 双向BFS)
- Qt网络编程之QNetworkReply
- Java开发中所需要的jar包
- 传智播客C/C++学院年薪24-50万招聘C/C++讲师
- 数据分析方法
- 一起学WF3.5【7】
- OpenCV和MFC一起用的时候出现内存泄露
- Hdu 4634 DP|最短路
- #杂问#什么是servlet??