洛谷OJ P1379 八数码难题 解题报告
2015-05-16 23:41
211 查看
洛谷OJ P1379 八数码难题 解题报告
by MedalPluS题目描述
在3×3的棋盘上,摆有八个棋子,每个棋子上标有1至8的某一数字。棋盘中留有一个空格,空格用0来表示。空格周围的棋子可以移到空格中。要求解的问题是:给出一种初始布局(初始状态)和目标布局(为了使题目简单,设目标状态为123804765),找到一种最少步骤的移动方法,实现从初始布局到目标布局的转变。
输入格式
输入初试状态,一行九个数字,空格用0表示
输出格式
只有一行,该行只有一个数字,表示从初始状态到目标状态需要的最少移动次数(测试数据中无特殊无法到达目标状态数据)
分析
其实就是个裸的BFS,但是可以拓展很多知识点(有人说不做这题的人的OI人生不完美)
暴力BFS的话会被卡,因为要搜索的状态实在太多了
所以这里有两种优化:
1.启发式搜索
我们假设f=g+h,那么g可以设为已经挪动的步数,h为不在位将牌个数,这样就构建了一个估价函数
然后直接写就好
2.双向BFS
我们知道起点和终点,直接双向就好
另外,这里应该如何判重呢?其实很简单,下面引入康托展开:/article/1461578.html
然后就利用康托值进行判重就好
代码
#include <iostream> #include <cstdio> #include <queue> #include <cstdlib> using namespace std; #define rep(i,l,r) for(i=l;i<=r;i++) const int maxn=10; const int maxm=1000001;//9!*8+8!*7...<=5000001 struct node{ int a[maxn][maxn]; short int g; node(){g=0;} }Head,Tail; short int vis_f[maxm],vis_b[maxm]; int tmps[maxn]; queue<node> f,b; int fact(int x){ int ans; for(ans=1;x>=2;x--)ans*=x; return ans; } int Cantor(node now){//Cantor_Expand int i,j,t=0,res=0; rep(i,1,3) rep(j,1,3) tmps[t++]=now.a[i][j]; t=0; rep(i,0,8) { t=0; rep(j,i+1,8) if(tmps[j]<tmps[i]) t++; res+=t*fact(9-i-1); } return res; } void init_Front(){ Head.a[1][1]=1;Head.a[1][2]=2;Head.a[1][3]=3; Head.a[2][1]=8;Head.a[2][2]=0;Head.a[2][3]=4; Head.a[3][1]=7;Head.a[3][2]=6;Head.a[3][3]=5; Head.g=0; } void init_Back(){ int i,j; rep(i,1,3) rep(j,1,3) scanf("%1d",&Tail.a[i][j]); } void init(){ memset(vis_f,-1,sizeof(vis_f)); memset(vis_b,-1,sizeof(vis_b)); init_Front(); init_Back(); } void expand_f(){ node head,tmp; head=f.front(); f.pop(); int i,j,sx,sy; rep(i,1,3) rep(j,1,3) if(!head.a[i][j]) { sx=i; sy=j; break; } tmp=head; if(sx-1>0){ swap(tmp.a[sx-1][sy],tmp.a[sx][sy]); tmp.g++; if(vis_b[Cantor(tmp)]!=-1){cout<<tmp.g+vis_b[Cantor(tmp)];exit(0);} if(vis_f[Cantor(tmp)]==-1){ vis_f[Cantor(tmp)]=tmp.g; f.push(tmp); } } tmp=head; if(sx+1<=3){ swap(tmp.a[sx+1][sy],tmp.a[sx][sy]); tmp.g++; if(vis_b[Cantor(tmp)]!=-1){cout<<tmp.g+vis_b[Cantor(tmp)];exit(0);} if(vis_f[Cantor(tmp)]==-1){ vis_f[Cantor(tmp)]=tmp.g; f.push(tmp); } } tmp=head; if(sy-1>0){ swap(tmp.a[sx][sy-1],tmp.a[sx][sy]); tmp.g++; if(vis_b[Cantor(tmp)]!=-1){cout<<tmp.g+vis_b[Cantor(tmp)];exit(0);} if(vis_f[Cantor(tmp)]==-1){ vis_f[Cantor(tmp)]=tmp.g; f.push(tmp); } } tmp=head; if(sy+1<=3){ swap(tmp.a[sx][sy+1],tmp.a[sx][sy]); tmp.g++; if(vis_b[Cantor(tmp)]!=-1){cout<<tmp.g+vis_b[Cantor(tmp)];exit(0);} if(vis_f[Cantor(tmp)]==-1){ vis_f[Cantor(tmp)]=tmp.g; f.push(tmp); } } } void expand_b(){ node head,tmp; head=b.front(); b.pop(); int i,j,sx,sy; rep(i,1,3) rep(j,1,3) if(!head.a[i][j]) { sx=i; sy=j; break; } tmp=head; if(sx-1>0){ swap(tmp.a[sx-1][sy],tmp.a[sx][sy]); tmp.g++; if(vis_f[Cantor(tmp)]!=-1){cout<<tmp.g+vis_f[Cantor(tmp)];exit(0);} if(vis_b[Cantor(tmp)]==-1){ vis_b[Cantor(tmp)]=tmp.g; b.push(tmp); } } tmp=head; if(sx+1<=3){ swap(tmp.a[sx+1][sy],tmp.a[sx][sy]); tmp.g++; if(vis_f[Cantor(tmp)]!=-1){cout<<tmp.g+vis_f[Cantor(tmp)];exit(0);} if(vis_b[Cantor(tmp)]==-1){ vis_b[Cantor(tmp)]=tmp.g; b.push(tmp); } } tmp=head; if(sy-1>0){ swap(tmp.a[sx][sy-1],tmp.a[sx][sy]); tmp.g++; if(vis_f[Cantor(tmp)]!=-1){cout<<tmp.g+vis_f[Cantor(tmp)];exit(0);} if(vis_b[Cantor(tmp)]==-1){ vis_b[Cantor(tmp)]=tmp.g; b.push(tmp); } } tmp=head; if(sy+1<=3){ swap(tmp.a[sx][sy+1],tmp.a[sx][sy]); tmp.g++; if(vis_f[Cantor(tmp)]!=-1){cout<<tmp.g+vis_f[Cantor(tmp)];exit(0);} if(vis_b[Cantor(tmp)]==-1){ vis_b[Cantor(tmp)]=tmp.g; b.push(tmp); } } } void double_BFS(){ int len1,len2; f.push(Head);b.push(Tail); vis_f[Cantor(Head)]=vis_b[Cantor(Tail)]=0; while(!f.empty() || !b.empty()){ len1=f.size();len2=b.size(); if(len1>len2){ if(len2)expand_b(); expand_f(); } else { if(len1)expand_f(); expand_b(); } } } int main(){ init(); double_BFS(); return 0; }
代码量比较大,竟然有个小200....
相关文章推荐
- codevs 1225 八数码难题 搜索+Hash 解题报告
- hdoj 2045 LELE的RPG难题 解题报告(简单递推)
- HDU1251 统计难题 解题报告--字典树
- uva1354 天平难题 解题报告
- hdoj 2045 不容易系列之(3)—— LELE的RPG难题 解题报告(简单递推)
- ***HDU-1272 小希的迷宫 ACM解题报告(并查集难题)
- [UVA10181]十五数码解题报告
- POJ1182 食物链 ACM解题报告(并查集+路径压缩难题)
- 八数码——解题报告
- 八数码解题报告
- HDOJ-1251-统计难题 解题报告
- [BZOJ3698]XWW的难题解题报告|上下界网络流|有源汇最大流
- YT03-递推求解课后题目-1003 不容易系列之(3)—— LELE的RPG难题-(6.7日-烟台大学ACM预备队解题报告)
- HDOJ 1251 统计难题——第二次用字典树AC题目,写一下解题报告
- NYOJ 478 月老的难题 (1)解题报告
- 杭电 HOJ 1251 统计难题 解题报告
- 问题测试数据NYOJ 478 月老的难题 (1)解题报告
- 八数码解题报告(转载)
- 【POJ1077】Eight 八数码问题,解题报告+思路+代码
- 洛谷 1171 售货员的难题 状压DP 解题报告