POJ 1077 八数码问题

来源:互联网 发布:mac 把自己改为管理员 编辑:程序博客网 时间:2024/06/08 00:35

传送门:POJ1077

题意:经典八数码问题求解。建议做之前先看一下http://www.cnblogs.com/goodness/archive/2010/05/04/1727141.html,八数码问题的八种境界,不过个人感觉其中的hash部分讲的有问题,至少和代码中的hash方法不一样,不过也有可能是我理解的不到位,不管怎样,以代码为准吧,而且这篇博客其他部分写的还挺好的。

我这里用的是上面博客中提到的hash+小顶堆+A*+曼哈顿距离

至于A*就自行百度吧,也可以看挑战程序设计356页。

这里贴上一个A*讲的通俗易懂的博客:http://www.cppblog.com/mythit/archive/2009/04/19/80492.aspx

代码:

#include<stdio.h>#include<iostream>#include<string.h>#include<math.h>#include<algorithm>#include<queue>#include<stack>#include<set>#include<vector>#include<map>#define ll long long#define pi acos(-1)#define inf 0x3f3f3f3fusing namespace std;typedef pair<int,int>P;int factorial[9]={1,1,2,6,24,120,720,5040,40320};int go[4][2]={1,0,0,1,-1,0,0,-1};int pos[9][2]={0,0,0,1,0,2,1,0,1,1,1,2,2,0,2,1,2,2};bool book[500000];int pre[500000];char res[500000];char dir[5]="drul";//A*   f=g+hstruct node{int f,g,h;int mp[3][3];int r,c;//'x'的坐标 friend bool operator <(node a,node b){if(a.f==b.f)return a.g<b.g;return a.f>b.f;//选较小的f和较大的g }}st;bool check(node t){int s[10];int cnt=0;for(int i=0;i<3;i++){for(int j=0;j<3;j++){s[i*3+j]=t.mp[i][j];if(t.mp[i][j]==9)continue;for(int k=0;k<i*3+j;k++){if(s[k]==9)continue;if(s[k]>s[i*3+j])cnt++;}}}return cnt&1;}int Hash(node t){int s[10];int cnt=0,sum=0;for(int i=0;i<3;i++){for(int j=0;j<3;j++){s[i*3+j]=t.mp[i][j];cnt=0;for(int k=0;k<i*3+j;k++){if(s[k]>s[i*3+j])cnt++;}sum+=factorial[i*3+j]*cnt;}}return sum;}int get_h(node t){int ans=0;for(int i=0;i<3;i++){for(int j=0;j<3;j++){if(t.mp[i][j]==9)continue;ans+=(abs(i-pos[t.mp[i][j]-1][0])+abs(j-pos[t.mp[i][j]-1][1]));}}return ans;}void bfs(){memset(book,0,sizeof(book));priority_queue<node>q;while(!q.empty())q.pop();q.push(st);book[Hash(st)]=1;while(!q.empty()){node t=q.top(),a;q.pop();int head=Hash(t);for(int i=0;i<4;i++){a=t;a.r+=go[i][0];a.c+=go[i][1];if(a.c<0||a.r<0||a.r>2||a.c>2)continue;a.mp[t.r][t.c]=t.mp[a.r][a.c];a.mp[a.r][a.c]=9;int x=Hash(a);if(book[x])continue;book[x]=1;a.g++;a.h=get_h(a);a.f=a.g+a.h;q.push(a);pre[x]=head;res[x]=dir[i];if(!x)//因为最后的目标状态hash值为0,所以x==0时结束搜索return ;}}}void solve(){st.g=0;st.h=get_h(st);st.f=st.g+st.h;bfs();stack<char>s;int front=Hash(st),rear=0;while(rear!=front){s.push(res[rear]);rear=pre[rear];}while(!s.empty())printf("%c",s.top()),s.pop();puts(""); }int main(){char s[100];while(gets(s)){int len=strlen(s),r=0,c=0;for(int i=0;i<len;i++){if(s[i]==' ')continue;if('0'<=s[i]&&s[i]<='9')st.mp[r][c]=s[i]-'0';else if(s[i]=='x'){st.mp[r][c]=9;st.r=r;st.c=c;}c++;r+=c/3;c%=3;}if(check(st)){printf("unsolvable\n");continue;}solve();}    return 0;}
PS:这里的hash方法是康托展开(自行百度)。另外就是这题有很多很多解法,什么双向bfs,IDA*都可以,挑自己喜欢的写就好。

0 0