题目描述 Description
Yours和zero在研究A*启发式算法.拿到一道经典的A*问题,但是他们不会做,请你帮他们.
问题描述
在3×3的棋盘上,摆有八个棋子,每个棋子上标有1至8的某一数字。棋盘中留有一个空格,空格用0来表示。空格周围的棋子可以移到空格中。要求解的问题是:给出一种初始布局(初始状态)和目标布局(为了使题目简单,设目标状态为123804765),找到一种最少步骤的移动方法,实现从初始布局到目标布局的转变。
输入描述 Input Description
输入初试状态,一行九个数字,空格用0表示
输出描述 Output Description
只有一行,该行只有一个数字,表示从初始状态到目标状态需要的最少移动次数(测试数据中无特殊无法到达目标状态数据)
样例输入 Sample Input
283104765
样例输出 Sample Output
4
不加A*也能过,加了跑得贼快
代码bfs,优先取出F[i]较小的点
F[i] = g[i] +h[i],其中g[i]为已走步数,h[i]为不在位的数码个数
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<queue>
using namespace std;
const int MAXN = 15;
int SS[] = {0,1,2,3,8,0,4,7,6,5};
const int M_S = 100000009;
struct zt
{
int a[MAXN];
int f;
int loc;
int step;
};
bool operator < (zt a,zt b)
{
return a.f + a.step > b.f + b.step;
}
int F(zt x)
{
int ans = 0;
for(int i = 1;i <= 9;i ++)
if(x.a[i] != SS[i])ans ++;
return ans;
}
priority_queue <zt> q;
char C[15];
int mu[] = {-1,1,-3,3};
zt x;
bool hash[M_S + 1];
bool can(zt u)
{
int ans = 0;
for(int i = 1;i <= 9;i ++)
{
ans = ((ans%M_S)*(10%M_S))%M_S;
ans += u.a[i];
}
if(hash[ans])return false;
hash[ans] = true;
return true;
}
int main()
{
scanf("%s",C + 1);
for(int i = 1;i <= 9;i ++)
{
x.a[i] = C[i] - '0';
if(!x.a[i])x.loc = i;
}
x.f = F(x);
q.push(x);
while(!q.empty())
{
zt u = q.top();
q.pop();
for(int i = 0;i <= 3;i ++)
{
int loc = u.loc + mu[i];
if(u.loc <= 3 && mu[i] == -3)
continue;
if(u.loc > 6 && mu[i] == 3)
continue;
if(u.loc % 3 == 0 && mu[i] == 1)
continue;
if(u.loc % 3 == 1 && mu[i] == -1)
continue;
zt t = u;
t.loc = loc;
swap(t.a[loc],t.a[u.loc]);
t.f = F(t);
t.step = u.step + 1;
if(can(t))q.push(t);
if(t.f == 0)
{
printf("%d",t.step);
return 0;
}
}
}
return 0;
}

本文介绍了一个使用A*算法解决8数码问题的方法。通过定义启发式函数并结合广度优先搜索策略,实现了从任意初始状态到目标状态的最短路径寻找。文章提供了完整的代码实现,并解释了关键步骤。
5961

被折叠的 条评论
为什么被折叠?



