HDU:1043 八数码问题
2015-02-20 20:33
267 查看
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1043
这题我看了有好多方法,但这其中最好理解的一种莫过于“打表法”,所谓打表,就是枚举所有起点到终点状态的路径。如果顺序打表,就会调用很多次BFS,这时我们可以用逆序打表的方式,只要调用一次BFS就可以了,但是,这样最大的缺点,我想应该是占用内存太大。所以,我们可以这样想,只要是与边权无关的路径存在问题,应该都可以用打表法来做的,当然这只是个人猜想,还待实践进行检验。
第一次用的是STL的queue时间达到了2s,内存18+m,后来改用自己写的队列,将时间提高到了600ms+,但是内存达到了27m,到了这里,可以看出,动手写的队列比STL快出很多,看到有人说swap比较慢,在这里我也验证了一下,根据结果来看,swap没多大影响,那就继续用吧。
还有这题让我知道了一个新东西,那就是康托展开:http://baike.baidu.com/link?url=yYNpVpo_tDQx9TJk6y6Ef21v4iUZffcAnOWrx1ivIeW_a8NkVfsPwiMqeJxm1ltCn5-obpDU1yv1FFkNXzGT5q
代码:(欢迎各位提出宝贵的建议)
这题我看了有好多方法,但这其中最好理解的一种莫过于“打表法”,所谓打表,就是枚举所有起点到终点状态的路径。如果顺序打表,就会调用很多次BFS,这时我们可以用逆序打表的方式,只要调用一次BFS就可以了,但是,这样最大的缺点,我想应该是占用内存太大。所以,我们可以这样想,只要是与边权无关的路径存在问题,应该都可以用打表法来做的,当然这只是个人猜想,还待实践进行检验。
第一次用的是STL的queue时间达到了2s,内存18+m,后来改用自己写的队列,将时间提高到了600ms+,但是内存达到了27m,到了这里,可以看出,动手写的队列比STL快出很多,看到有人说swap比较慢,在这里我也验证了一下,根据结果来看,swap没多大影响,那就继续用吧。
还有这题让我知道了一个新东西,那就是康托展开:http://baike.baidu.com/link?url=yYNpVpo_tDQx9TJk6y6Ef21v4iUZffcAnOWrx1ivIeW_a8NkVfsPwiMqeJxm1ltCn5-obpDU1yv1FFkNXzGT5q
代码:(欢迎各位提出宝贵的建议)
#include<iostream> #include<sstream> #include<cstdio> #include<cstring> #include<cmath> #include<algorithm> #include<string> using namespace std; int fac[]={1,1,2,6,24,120,720,5040,40320,362880};//用于康托展开 int end[]={1,2,3,4,5,6,7,8,0}; int cantor(int *s){//相当于一个Hash函数,按照字符串大小顺序给每一个状态赋予一个值 int sum=0; for(int i=0;i<9;i++){ int cnt=0; for(int j=i+1;j<9;j++) if(s[j]<s[i]) cnt++; sum+=cnt*fac[9-i-1]; } return sum; } struct node{ int s[9]; int cur,n; }q[362890]; int vis[362890]; string ans[362890]; int d[][2]={{1,0},{-1,0},{0,-1},{0,1}}; void bfs(){ memset(vis,0,sizeof(vis)); memcpy(q[0].s,end,sizeof(q[0].s)); q[0].n=cantor(q[0].s); q[0].cur=8; vis[q[0].n]=1; int fr=0,ed=1; while(fr<ed) { node &tmp=q[fr]; fr++; int x=tmp.cur/3,y=tmp.cur%3; for(int p=0;p<4;p++){ int tx=x+d[p][0],ty=y+d[p][1]; if(tx>=0 && ty>=0 && tx<3 && ty<3){ node &tmp2=q[ed]; memcpy(tmp2.s,tmp.s,sizeof(tmp2.s)); tmp2.cur=tx*3+ty; swap(tmp2.s[x*3+y],tmp2.s[tx*3+ty]); tmp2.n=cantor(tmp2.s); tmp2.cur=tx*3+ty; if(!vis[tmp2.n]){ vis[tmp2.n]=1; ans[tmp2.n]=ans[tmp.n]; if(tx>x) ans[tmp2.n]+='u';//由于是逆序打表,所以这里需要按反方向记录 else if(tx<x) ans[tmp2.n]+='d'; else if(ty>y) ans[tmp2.n]+='l'; else ans[tmp2.n]+='r'; ed++; } } } } } int main(){ bfs();//打表,并用ans记录逆序到达每一个状态的路径 node t; char ch; while(cin>>ch){ if(ch=='x'){ ch='0'; } t.s[0]=ch-'0'; for(int i=1;i<9;i++){ cin>>ch; if(ch=='x') ch='0'; t.s[i]=ch-'0'; } t.n=cantor(t.s);//接下来就是一个简单的查找过程了 if(!vis[t.n]) cout<<"unsolvable\n"; else { reverse(ans[t.n].begin(),ans[t.n].end()); cout<<ans[t.n]<<endl; } } return 0; }
相关文章推荐
- poj 1077 hdu 1043 Eight 八数码问题 DBFS(双向广度优先搜索)a*算法 康拓展开
- bfs+hash poj 1077/hdu 1043 八数码问题
- HDU-1043 Eight 八数码问题
- [算法入门经典] 7.5.3 八数码问题 | HDU 1043
- HDU 1043 八数码问题 A*搜索
- hdu1043 八数码问题
- HDU 1043 / POJ 1077 Eight(八数码问题)
- hdu 1043 Eight 经典八数码问题
- HDU 1043 Eight ((八数码问题)逆向BFS + 康托定理判重)
- Hdu 1043 Eight (八数码问题)
- hdu 1043 八数码问题-A*搜索
- HDU 1043 Eight 八数码问题 A*搜索 启发式算法
- POJ 1077 Eight && HDU 1043 Eight 八数码问题(A*算法)
- HDU 1043 Eight (经典八数码问题,BFS+状态枚举+伪哈希)
- HDU 1043 Eight(经典八数码问题)对比POJ 1077
- HDU 1043 八数码问题 A*搜索
- 八数码问题(HDU 1043)
- HDU1043 Eight 八数码问题
- 八数码问题——HDU 1043
- hdu 1043-Eight(经典八数码问题)(单向广搜 A* 状态压缩)