当前位置: 代码迷 >> 综合 >> poj 1077 Eight A*解八数码问题
  详细解决方案

poj 1077 Eight A*解八数码问题

热度:22   发布时间:2024-01-19 05:40:18.0

题意:

经典的八数码问题。

分析:

搜索算法的区别是如何重排open表,关键是如何编码状态和定义状态的值。对搜索过程中任意状态s,A*算法以g(s)+h(s)重排open表,也就是说g(s)+h(s)是排列open中状态的依据,其中g(s)是初始状态到s的消耗,h(s)是s到目标状态的估计。我重排open用的是c++的优先队列,扩展状态s得到新的状态ns,如果ns没访问过则直接将ns及其节点加入open。如果ns已经访问过(在open或close中),则更新ns的g(s)和h(s),由于无法直接在优先队列中进行更新,所以需要在外部用全局数组记录各个状态的g值,当某个状态的g值要改变时重新加入包含这个状态的节点,这样有冗余但不影响正确性,也是优先队列优化dijkstra算法的方法。关于启发函数h(s),h(s)越大则占g(s)+h(s)的比重越大,程序的速度也越快,当h(s)总小于实际到最终状态的消耗时,算法是能确定找到最优解的,否则能找到解但不一定能找到最优解(总消耗最少)。这题数据有问题,3*h(s)当启发函数是不能保证找到走过步数(消耗)最小的解的。

代码:

//poj 1077
//sep9
#include <iostream>
#include <queue>
#include <string> 
using namespace std;
const int maxN=500000;
const int aim=46233;
int fac[]={1,1,2,6,24,120,720,5040,40320};
int vis[maxN],g[maxN];
int dirx[]={0,0,-1,1};
int diry[]={-1,1,0,0};
int goal_x[]={0,0,0,1,1,1,2,2};
int goal_y[]={0,1,2,0,1,2,0,1};
char word[8]="lrud";struct NODE
{int s[9];int loc; //location of '0'int status;//cantor valueint f;//f=g+hstring path;bool operator <(const NODE &a) const{return f>a.f;}	
};
priority_queue<NODE> open;
string path;int cantor(int s[])
{int sum=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;sum+=cnt*fac[9-i-1];}return sum;		
}int h(int s[])
{int sum=0;for(int i=0;i<3;++i)for(int j=0;j<3;++j){int k=i*3+j;if(s[k]!=9)sum+=abs(i-goal_x[s[k]-1])+abs(j-goal_y[s[k]-1]);}return sum;
}int a_star(NODE start)
{memset(vis,0,sizeof(vis));	while(!open.empty()) open.pop();NODE cur,nxt;open.push(start);vis[start.status]=1;while(!open.empty()){cur=open.top();open.pop();if(cur.status==aim){path=cur.path;return 1;}int x=cur.loc/3;int y=cur.loc%3;for(int i=0;i<4;++i){int tx=x+dirx[i];int ty=y+diry[i];if(tx<0||tx>=3||ty<0||ty>=3)continue;nxt=cur;nxt.loc=tx*3+ty;nxt.s[cur.loc]=nxt.s[nxt.loc];nxt.s[nxt.loc]=0;nxt.status=cantor(nxt.s);if(vis[nxt.status]==0){//0:not visited 1:in colse or openvis[nxt.status]=1;g[nxt.status]=g[cur.status]+1;nxt.f=g[nxt.status]+3*h(nxt.s);//h>h* can not always found the best solution,but can find a solution nxt.path=nxt.path+word[i];open.push(nxt);}/*else if(vis[nxt.status]==1&&g[cur.status]+1<g[nxt.status]){//bfs dis[i][j]==1  ==> g[cur]+1>=g[nxt]//	nxt.f=nxt.f-g[nxt.status]+g[cur.status]+1;//update nxt.status//	g[nxt.status]=g[cur.status]+1;//	nxt.path=nxt.path+word[i];//	open.push(nxt);}*/}vis[cur.status]=1;}return 0;
}int main()
{char tmp[4];NODE ncur;for(int i=0;i<9;++i){scanf("%s",tmp);if(tmp[0]=='x'){ncur.s[i]=0;ncur.loc=i;}elsencur.s[i]=tmp[0]-'0';}ncur.status=cantor(ncur.s);g[ncur.status]=0;ncur.f=h(ncur.s);if(a_star(ncur))cout<<path;elseputs("unsolvable");return 0;	
}