您的位置:首页 > 其它

POJ 1077 Eight 八数码问题 A*

2014-11-26 19:27 381 查看
题意:经典的八数码问题。

思路:我们这里用A*搜索来解决问题。

在A*算法中,我们定义一个h函数表示当前状态到目标需要的至少的步数。这样,在搜索的过程中,我们取出可能更接近目标的状态进行扩展,所以能更快的接近目标。

而对于这道题,定义h函数为每个数字到正确的位置,如果直接移动所需要的步数。可以看到,h函数是实际步数的下界,这个在A*中是十分重要的。

#include <cstdio>
#include <algorithm>
#include <cstring>
#include <queue>

using namespace std;

const int MAX = 400010;

int dx[] = {0,0,-1,1};
int dy[] = {1,-1,0,0};
char dir[] = {'r','l','u','d'};
int pos[][2] = {0,0,0,0,0,1,0,2,1,0,1,1,1,2,2,0,2,1};
int fact[20],d[MAX],fa[MAX],path[MAX];
bool vis[MAX];

void init()
{
fact[0] = 1;
for(int i = 1; i < 9; ++i)
fact[i] = fact[i-1] * i;
}

struct node{
int s[9];
int d,h,v;
node(){}
node(int t[9]){
d = 0;
memcpy(s,t,sizeof(t));
}
bool operator < (const node & rhs) const{
return d + h > rhs.d + rhs.h;
}
void cantor(){
v = 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++;
v += fact[8 - i] * cnt;
}
}
void hstar(){
h = 0;
for(int i = 0; i < 3; ++i){
for(int j = 0; j < 3; ++j){
int z = 3 * i + j;
int x = s[z];
h += abs(pos[x][0] - i) + abs(pos[x][1] - j);
}
}
}
};

node st;

priority_queue<node> Q;

bool Astar()
{
while(!Q.empty()) Q.pop();
Q.push(st);vis[st.v] = true;
while(!Q.empty()){
node t = Q.top();Q.pop();
if(t.v == 46233) return true;
for(int i = 0; i < 9; ++i) if(t.s[i] == 0){
int x = i / 3, y = i % 3;
for(int k = 0; k < 4; ++k){
int nx = x + dx[k], ny = y + dy[k];
if(nx >= 0 && nx < 3 && ny >= 0 && ny < 3){
node tt = t;
int nz = 3 * nx + ny;
swap(tt.s[i],tt.s[nz]);
tt.cantor();tt.hstar();
if(!vis[tt.v]){
vis[tt.v] = true;
d[tt.v] = k;
fa[tt.v] = t.v;
tt.d += 1;
Q.push(tt);
}
}
}
}
}
return false;
}

char str[100];

int main(void)
{
//freopen("input.txt","r",stdin);
init();
while(~scanf("%s",str)){
memset(vis,0,sizeof(vis));
if(!sscanf(str,"%d",&st.s[0])) st.s[0] = 0;
for(int i = 1; i < 9; ++i){
scanf("%s",str);
if(!sscanf(str,"%d",&st.s[i])) st.s[i] = 0;
}
st.cantor();st.hstar(); st.d = 0;
if(!Astar())
puts("unsolvable");
else{
int sz = 0;
for(int v = 46233; v != st.v; v = fa[v])
path[sz++] = d[v];
for(int i = sz - 1; i >= 0; --i)
putchar(dir[path[i]]);
puts("");
}
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: