数据结构算法: 八数码问题 小结
2017-05-18 21:23
369 查看
问题定义
算法流程
相关搜索策略
单向BFS搜索
双向BFS搜索
逆向BFS离线打表
A启发式搜索算法
八数码问题变种解法 hdu3567
好久没写博客了,最近开始更一个系列,关于数据结构算法的,希望能形成一个好的体系。 之前写的博文是零碎的知识点小结,只适合自己回顾,不适合他人阅读或者教学,希望这个系列能改善相关的问题,方便他人阅读,分享知识。
八数码问题一般使用搜索法来解。搜索法有广度优先搜索法、双向广度优先算法、深度优先搜索法、A*算法等。这里通过用不同方法解八数码问题来比较一下不同搜索法的效果。关于搜索问题,往往重要的是相关的搜索策略的选择。策略选择的好,效率就会有非常大的差异。
oj题目:PKU(1077) HDOJ(1043) ZOJ(1217) 由于测试数据的不同各平台状态不同
变种:hdu 3567等
根据环境选择搜索策略进行搜索求解,本文以典型的搜索算法: BFS,双向BFS, 离线算法,A*算法为例进行讲解
算法流程
相关搜索策略
单向BFS搜索
双向BFS搜索
逆向BFS离线打表
A启发式搜索算法
八数码问题变种解法 hdu3567
好久没写博客了,最近开始更一个系列,关于数据结构算法的,希望能形成一个好的体系。 之前写的博文是零碎的知识点小结,只适合自己回顾,不适合他人阅读或者教学,希望这个系列能改善相关的问题,方便他人阅读,分享知识。
问题定义
八数码问题: 在3×3的棋盘,摆有八个棋子,每个棋子上标有1至8的某一数字,不同棋子上标的数字不相同。棋盘上还有一个空格,与空格相邻的棋子可以移到空格中。要求解决的问题是:给出一个初始状态和一个目标状态,找出一种从初始转变成目标状态的移动棋子步数最少的移动步骤。所谓问题的一个状态就是棋子在棋盘上的一种摆法。棋子移动后,状态就会发生改变。解八数码问题实际上就是找出从初始状态到达目标状态所经过的一系列中间过渡状态。八数码问题一般使用搜索法来解。搜索法有广度优先搜索法、双向广度优先算法、深度优先搜索法、A*算法等。这里通过用不同方法解八数码问题来比较一下不同搜索法的效果。关于搜索问题,往往重要的是相关的搜索策略的选择。策略选择的好,效率就会有非常大的差异。
oj题目:PKU(1077) HDOJ(1043) ZOJ(1217) 由于测试数据的不同各平台状态不同
变种:hdu 3567等
算法流程:
cantor算法+奇偶性判断(或者逆序对数目判断)是否存在解,若有解,转2; 否则退出根据环境选择搜索策略进行搜索求解,本文以典型的搜索算法: BFS,双向BFS, 离线算法,A*算法为例进行讲解
相关搜索策略
单向BFS搜索
#include<iostream> #include<cstdio> #include<cstring> //#include<vector> #include<algorithm> #include<queue> #include<map> #ifdef L_JUDGE #pragma warning(disable:4996) #endif using namespace std; typedef pair<int,char> pic; struct Node{ int s[9]; int ri,ci; int status; int cnt; Node(){ memset(s,0,sizeof(s)); ri=ci=0; status=-1; cnt=0; } }; const int dir[4][2]={-1,0,1,0,0,-1,0,1}; char in[20]; Node st,ed; queue<Node> Q; int fac[9]; bool vis[(int)4e5+10]; map<int,pair<int,int> >pre; bool InMap(int ri,int ci){ return ri>=0&&ri<3&&ci>=0&&ci<3; } int Cantor(int s[]){ int ret=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++; } ret+=cnt*fac[8-i]; } return ret; } int BFS(const Node& st,int edval){ memset(vis,false,sizeof(vis)); while(!Q.empty())Q.pop(); pre.clear(); Q.push(st); vis[st.status]=true; pre[st.status]=make_pair(-1,-1); while(!Q.empty()){ Node u=Q.front(); Q.pop(); if(u.status==edval)return u.cnt; for(int di=0;di<4;di++){ Node v=u; v.ri=u.ri+dir[di][0]; v.ci=u.ci+dir[di][1]; if(!InMap(v.ri,v.ci))continue; int upos=3*u.ri+u.ci; int vpos=3*v.ri+v.ci; swap(v.s[upos],v.s[vpos]); v.status=Cantor(v.s); if(vis[v.status])continue; vis[v.status]=true; v.cnt=u.cnt+1; 4000 Q.push(v); pre[v.status]=make_pair(u.status,di); if(v.status==edval)return v.cnt; } } return -1; } int main(){ #ifdef L_JUDGE freopen("in.txt","r",stdin); // freopen("out.txt","w",stdout); #endif fac[0]=1; for(int i=1;i<9;i++)fac[i]=i*fac[i-1]; ed.ri=ed.ci=2; for(int i=0;i<9;i++){ ed.s[i]=i+1; } ed.status=Cantor(ed.s); while(cin>>in[0]){ for(int i=1;i<9;i++)cin>>in[i]; for(int ri=0;ri<9;ri++){ if('x'==in[ri]){ st.s[ri]=9; st.ri=ri/3; st.ci=ri%3; } else st.s[ri]=in[ri]-'0'; } st.status=Cantor(st.s); st.cnt=0; int flag=BFS(st,ed.status); if(-1==flag)puts("unsolvable"); else{ char ans[1000]; char ch[5]="udlr"; int k=ed.status; ans[flag]=0; while(k!=st.status){ flag--; ans[flag]=ch[pre[k].second]; k=pre[k].first; } puts(ans); } } #ifdef L_JUDGE fclose(stdin); fclose(stdout); // system("out.txt"); #endif return 0; }
双向BFS搜索
#include<iostream> #include<cstdio> #include<cstring> //#include<vector> #include<algorithm> #include<queue> #ifdef L_JUDGE #pragma warning(disable:4996) #endif using namespace std; const int MAXN=5e5; const int MAXM=6; const int MAXS=1025; const int MOD=1e9+7; char visited[MAXN]; int father1[MAXN]; int father2[MAXN]; int move1[MAXN]; int move2[MAXN]; struct Status{ char eight[10]; int space; int status; }; Status s,s1,s2,t; queue<Status> Q1; queue<Status> Q2; bool found; int status; int fac_n[]={1,1,2,6,24,120,720,5040,40320,362880}; const int dir[4][2]={-1,0,1,0,0,-1,0,1}; int Cantor(char s[]){ int ret=0; for(int i=0;i<9;i++){ int cnt=0; for(int j=i+1;j<9;j++){ if(s[i]>s[j])cnt++; } ret+=cnt*fac_n[9-1-i]; } return ret; } bool bSolve(char s[]){ int cnt=0; for(int i=0;i<9;i++){ if(s[i]==9)continue; for(int j=i+1;j<9;j++){ if(s[j]==9)continue; if(s[i]>s[j])cnt++; } } if(1&cnt)return false; else return true; } bool InMap(int ri,int ci){ return ri>=0&&ri<3&&ci>=0&&ci<3; } void BFS_expand(queue<Status> &Q,bool flag){ int k,x,y; s=Q.front(); Q.pop(); k=s.space; x=k/3;y=k%3; for(int di=0;di<4;di++){ int xx=x+dir[di][0]; int yy=y+dir[di][1]; if(!InMap(xx,yy))continue; t=s; t.space=3*xx+yy; swap(t.eight[t.space],t.eight[s.space]); t.status=Cantor(t.eight); if(flag){ if(visited[t.status]!=1//&&(bSolve(t.eight)) ){ move1[t.status]=di; father1[t.status]=s.status; if(visited[t.status]==2){ found=true; status=t.status; return; } visited[t.status]=1; Q.push(t); } }else{ if(visited[t.status]!=2//&&(bSolve(t.eight)) ){ move2[t.status]=di; father2[t.status]=s.status; if(visited[t.status]==1){ found=true; status=t.status; return; } visited[t.status]=2; Q.push(t); } } } } void TBFS(){ memset(visited,0,sizeof(visited)); while(!Q1.empty())Q1.pop(); while(!Q2.empty())Q2.pop(); found=false; visited[s1.status]=1; visited[s2.status]=2; father1[s1.status]=-1; father2[s2.status]=-1; Q1.push(s1);Q2.push(s2); while((!Q1.empty()) ||(!Q2.empty())){ if(!Q1.empty())BFS_expand(Q1,true); if(found)return; if(!Q2.empty())BFS_expand(Q2,false); if(found)return; } } void PrintPath1(int father[],int move[]){ int n,u; char path[1000]; n=0; u=status; while(father[u]!=-1){ path[n++]=move[u]; u=father[u]; } for(int i=n-1;i>=0;i--){ switch(path[i]){ case 0: putchar('u'); break; case 1: putchar('d'); break; case 2: putchar('l'); break; case 3: putchar('r'); break; } } } void PrintPath2(int father[],int move[]){ int n,u; char path[1000]; n=0; u=status; while(father[u]!=-1){ path[n++]=move[u]; u=father[u]; } for(int i=0;i<n;i++){ switch(path[i]){ case 0: putchar('d'); break; case 1: putchar('u'); break; case 2: putchar('r'); break; case 3: putchar('l'); break; } } } int main(){ #ifdef L_JUDGE freopen("in.txt","r",stdin); // freopen("out.txt","w",stdout); #endif char ch; while(cin>>ch){ if(ch=='x 12c07 '){ s1.eight[0]=9; s1.space=0; }else{ s1.eight[0]=ch-'0'; } for(int i=1;i<9;i++){ cin>>ch; if(ch=='x'){ s1.eight[i]=9; s1.space=i; }else{ s1.eight[i]=ch-'0'; } } s1.status=Cantor(s1.eight); for(int i=0;i<9;i++){ s2.eight[i]=(i+1); } s2.space=8; s2.status=Cantor(s2.eight); if(!bSolve(s1.eight)){ puts("unsolvable"); }else{ TBFS(); if(found){ if(s1.status!=status)PrintPath1(father1,move1); if(s2.status!=status)PrintPath2(father2,move2); putchar('\n'); }else puts("unsolvable"); } } #ifdef L_JUDGE fclose(stdin); fclose(stdout); // system("out.txt"); #endif return 0; }
逆向BFS+离线打表
#include<iostream> #include<cstdio> #include<cstring> //#include<vector> #include<algorithm> #include<queue> #ifdef L_JUDGE #pragma warning(disable:4996) #endif using namespace std; const int MAXN=5e5+10; const int MAXM=6; const int MAXS=1025; const int MOD=1e9+7; const int dir[4][2]={-1,0,1,0,0,-1,0,1}; struct Node{ public: int s[9]; int status; int ri,ci; Node(){ ri=ci=0; status=0; memset(s,0,sizeof(s)); } }st,ed; int fac_n[10]; pair<int,int> path[MAXN]; bool vis[MAXN]; int Cantor(int s[]){ int ret=0; for(int i=0;i<9;i++){ int cnt=0; for(int j=i+1;j<9;j++){ if(s[i]>s[j])cnt++; } ret+=fac_n[9-i-1]*cnt; } return ret; } bool InMap(int ri,int ci){ return ri>=0&&ri<3&&ci>=0&&ci<3; } void BFS(){ for(int i=0;i<9;i++){ ed.s[i]=i+1; } ed.ri=ed.ci=2; ed.status=Cantor(ed.s); memset(vis,false,sizeof(vis)); memset(path,-1,sizeof(path)); queue<Node> Q; Q.push(ed); vis[ed.status]=true; path[ed.status]=make_pair(-1,-1); while(!Q.empty()){ Node u=Q.front(); Q.pop(); for(int di=0;di<4;di++){ Node v=u; v.ri=u.ri+dir[di][0]; v.ci=u.ci+dir[di][1]; if(!InMap(v.ri,v.ci))continue; swap(v.s[3*v.ri+v.ci],v.s[3*u.ri+u.ci]); v.status=Cantor(v.s); if(vis[v.status])continue; vis[v.status]=true; path[v.status]=make_pair(u.status,di); Q.push(v); } } } char chd[10]="durl"; char ans[MAXN],anslen; bool Print(int s,int t){ if(s==t)return true; if(s==-1)return false; ans[anslen++]=chd[path[s].second]; bool flag=Print(path[s].first,t); return flag; } int main(){ #ifdef L_JUDGE freopen("in.txt","r",stdin); // freopen("out.txt","w",stdout); #endif fac_n[0]=fac_n[1]=1; for(int i=2;i<=9;i++)fac_n[i]=i*fac_n[i-1]; BFS(); char input[50]; while(cin.getline(input,50,'\n')){ int si=0; for(int i=0;input[i];i++){ if(input[i]!=' '){ if(input[i]=='x'){ st.ri=si/3; st.ci=si%3; st.s[si]=9; }else{ st.s[si]=input[i]-'0'; } si++; } } st.status=Cantor(st.s); int k=st.status; anslen=0; memset(ans,0,sizeof(ans)); bool flag=Print(st.status,ed.status); if(!flag)puts("unsolvable"); else puts(ans); } #ifdef L_JUDGE fclose(stdin); fclose(stdout); // system("out.txt"); #endif return 0; }
A*启发式搜索算法
#include<iostream> #include<cstdio> #include<cstring> //#include<vector> #include<algorithm> #include<cstdlib> #include<queue> #ifdef L_JUDGE #pragma warning(disable:4996) #endif using namespace std; const int MAXN=5e5+10; const int MAXM=6; const int MAXS=1025; const int MOD=1e9+7; struct Node{ public: int s[9]; int ri,ci; int status; int f,g,h; Node(){ ri=0;ci=0; memset(s,0,sizeof(s)); status=0; } bool operator<(const Node& p) const{ if(f<p.f)return false; else if((f==p.f)&&(h<p.h))return false; return true; } }; const int dir[4][2]={-1,0,1,0,0,-1,0,1}; const char d[10]="udlr"; char input[50]; int fac_n[10]; Node st,ed; bool vis[MAXN]; void Init(){ fac_n[0]=fac_n[1]=1; for(int i=2;i<9;i++){ fac_n[i]=i*fac_n[i-1]; } } int Cantor(int a[]){ int ret=0; for(int i=0;i<9;i++){ int cnt=0; for(int j=i+1;j<9;j++){ if(a[i]>a[j])cnt++; } ret+=cnt*fac_n[9-i-1]; } return ret; } bool bSolve(const Node &p){ int cnt=0; for(int i=0;i<9;i++){ for(int j=i+1;j<9;j++){ if(p.s[i]>p.s[j]&&p.s[i]&&p.s[j])cnt++; } } if(cnt&1)return false; else return true; } int Get_H(const Node &p){ int ret=0; for(int i=0;i<9;i++){ int t=p.s[i]-1; int ri=t/3; int ci=t%3; ret+=abs(ri-i/3)+abs(ci-i%3); } return ret; } bool InMap(int ri,int ci){ return ri>=0&&ri<3&&ci>=0&&ci<3; } priority_queue<Node> SQ; pair<int,int> path[MAXN]; void BFS(const Node &st,const Node &ed){ memset(vis,false,sizeof(vis)); memset(path,-1,sizeof(path)); while(!SQ.empty())SQ.pop(); SQ.push(st); path[st.status]=make_pair(-1,-1); vis[st.status]=true; while(!SQ.empty()){ Node u=SQ.top(); SQ.pop(); if(u.status==ed.status)return ; for(int di=0;di<4;di++){ Node v=u; v.ri=u.ri+dir[di][0]; v.ci=u.ci+dir[di][1]; if(!InMap(v.ri,v.ci))continue; int ti=3*v.ri+v.ci; swap(v.s[ti],v.s[3*u.ri+u.ci]); v.status=Cantor(v.s); if(vis[v.status])continue; vis[v.status]=true; v.g=u.g+1; v.h=Get_H(v); v.f=v.g+v.h; SQ.push(v); path[v.status]=make_pair(u.status,di); if(v.status==ed.status)return; } } } void Print(int si,int ed){ if(si==ed)return; Print(path[si].first,ed); putchar(d[path[si].second]); } int main(){ #ifdef L_JUDGE freopen("in.txt","r",stdin); // freopen("out.txt","w",stdout); #endif while(cin.getline(input,50,'\n')){ Init(); ed.ri=ed.ci=2; for(int i=0;i<9;i++){ ed.s[i]=(i+1)%9; } ed.status=Cantor(ed.s); int si=0; for(int i=0;input[i];i++){ if(input[i]!=' '){ if(input[i]=='x'){ st.s[si]=0; st.ri=si/3; st.ci=si%3; }else{ st.s[si]=input[i]-'0'; } si++; } } st.status=Cantor(st.s); st.g=0; st.h=Get_H(st); st.f=st.h+st.g; if(!bSolve(st)){ cout<<"unsolvable"<<endl; }else{ BFS(st,ed); int k=ed.status; Print(ed.status,st.status); printf("\n"); } } #ifdef L_JUDGE fclose(stdin); fclose(stdout); // system("out.txt"); #endif return 0; }
八数码问题变种解法 hdu3567
//重新编码初始状态和终点状态 //前期预处理+打表 #include<iostream> #include<cstdio> #include<cstring> //#include<vector> #include<algorithm> #include<queue> #define U_DEBUG #define L_JUDGE #ifdef L_JUDGE #pragma warning(disable:4996) #endif using namespace std; const int MAXN=4e5+10; const int fac_n[10]={1,1,2,6,24,120,720,5040,40320,362880}; const int dir[4][2]={1,0,0,-1,0,1,-1,0}; int father[9][MAXN]; char move1[9][MAXN]; bool vis[9][MAXN]; int Cantor(char s[]){ int ret=0; for(int i=0;i<9;i++){ int cnt=0; for(int j=i+1;j<9;j++){ if(s[i]>s[j])cnt++; } ret+=cnt*fac_n[9-i-1]; } return ret; } struct Status{ char eight[9]; int space; int status; Status(){ memset(eight,0,sizeof(eight)); space=0; status=0; } Status(char s[]){ for(int i=0;i<9;i++){ if(s[i]!='X'){ eight[i]=s[i]-'0'; } else { eight[i]=9; space=i; } } status=Cantor(eight); } }st,ed; int T,N; bool InMap(int ri,int ci){ return ri>=0&&ri<3&&ci>=0&&ci<3; } queue<Status> Q; void BFS(Status st,int pi){ while(!Q.empty())Q.pop(); memset(vis[pi],false,sizeof(vis[pi])); memset(move1[pi],-1,sizeof(move1[pi])); memset(father[pi],-1,sizeof(father[pi])); Q.push(st); vis[pi][st.status]=true; move1[pi][st.status]=-1; father[pi][st.status]=-1; while(!Q.empty()){ Status u=Q.front(); Q.pop(); int k=u.space; int x=k/3,y=k%3; for(int di=0;di<4;di++){ int xx=x+dir[di][0]; int yy=y+dir[di][1]; if(!InMap(xx,yy))continue; Status v=u; v.space=3*xx+yy; swap(v.eight[v.space],v.eight[k]); v.status=Cantor(v.eight); if(vis[pi][v.status])continue; vis[pi][v.status]=true; move1[pi][v.status]=di; father[pi][v.status]=u.status; Q.push(v); } } } int main(){ #ifdef L_JUDGE freopen("in.txt","r",stdin); // freopen("out.txt","w",stdout); #endif char str[20]="X12345678"; for(int i=0;i<9;i++){ st=Status(str); BFS(st,i); swap(str[i],str[i+1]); } scanf("%d",&T); for(int ti=1;ti<=T;ti++){ scanf("%s",str); st=Status(str); int pi=0; int mp[10],mpi=1; for(int i=0;i<9;i++){ if(str[i]=='X'){ pi=i; }else{ mp[str[i]-'0']=mpi++; } } scanf("%s",str); for(int i=0;i<9;i++){ if(str[i]!='X'){ str[i]=mp[str[i]-'0']+'0'; } } ed=Status(str); char ans[1010]; int anslen=0; int k=ed.status; while(father[pi][k]!=-1){ switch(move1[pi][k]){ case 0: ans[anslen++]='d'; break; case 1: ans[anslen++]='l'; break; case 2: ans[anslen++]='r'; break; case 3: ans[anslen++]='u'; break; } k=father[pi][k]; } for(int i=0,j=anslen-1;i<j;i++,j--) swap(ans[i],ans[j]); ans[anslen]=0; printf("Case %d: %d\n%s\n",ti,anslen,ans); } #ifdef L_JUDGE fclose(stdin); fclose(stdout); // system("out.txt"); #endif return 0; }
相关文章推荐
- [C++]数据结构:算法分析之八皇后问题
- 数据结构与算法实验题 11.3 最小权语言问题
- 数据结构算法问题 移动小球
- 数据结构与算法问题 二叉排序树
- 数据结构与算法问题 堆栈使用 2011年吉林大学计算机研究生机试真题
- 【数据结构与算法】约瑟夫环问题
- 数据结构——算法之(011)( 字符串是否包含问题)
- 数据结构与算法问题 二叉搜索树
- 数据结构算法问题 小球下落
- 数据结构与算法问题 朋友圈
- LeetCode 问题难度,面试出现频率及问题相关数据结构和算法
- [数据结构与算法]各种排序算法的稳定性和时间复杂度小结
- 数据结构与算法2:八皇后问题
- 数据结构与算法问题 二叉树
- 【并查集】数据结构与算法实验题 11.3 培养箱分配问题
- 数据结构与算法[LeetCode]—N_Queen问题
- 数据结构与算法学习笔记04(约瑟夫问题)
- 数据结构与算法实验题 11.3 最小权语言问题
- 数据结构与算法问题 欧拉回路
- 数据结构与算法问题 单源最短路径 浙大OJ